2009-11-03 16 views
6

मैं एक प्रकार Type.GetType (nameOfTheType), जहां nameOfTheType कुछ स्ट्रिंग है का उपयोग कर बनाना चाहते हैं। अगर nameOfTheType "System.String" है, तो यह बहुत अच्छा काम करता है। अगर nameOfTheType "स्ट्रिंग" है, तो यह अपवाद फेंकता है। कीवर्ड शॉर्टकट वाले सभी प्रकार असफल हो जाते हैं।सी # कीवर्ड से उचित प्रकार का नाम प्राप्त करने का सबसे अच्छा तरीका क्या है?

क्या कोई बड़ा तरीका है, एक बड़े स्विच स्टेटमेंट के अलावा, अपने वास्तविक प्रकार के नामों के लिए कीवर्ड शॉर्टकट के साथ सभी प्रकारों को सही ढंग से मानचित्र करने के लिए कोई तरीका है (इस सूची के अनुसार: http://msdn.microsoft.com/en-us/library/ya5y69ds%28VS.80%29.aspx)?

संपादित करें: गेब्रियल ने सही ढंग से बताया है कि एमएसडीएन पेज जो मैंने लिंक किया है, इसमें नामुमकिन प्रकार (int ?, आदि) शामिल नहीं है, लेकिन यह महत्वपूर्ण है कि नामुमकिन प्रकारों को भी सही तरीके से मैप किया जा सके।

+2

क्या आप इसे नलिकाओं के लिए भी काम करना चाहते हैं? उदाहरण के लिए। int? डबल,? इत्यादि – Gabriel

उत्तर

4

अस्वीकरण
ने मुझे बताया कि विधि मैं यहाँ प्रदर्शित करने के लिए जा रहा हूँ शैक्षिक उद्देश्यों के लिए विशुद्ध रूप से है द्वारा शुरू करते हैं। कृपया अपने उत्पादन कोड में अन्य उत्तरों में दिखाए गए स्विच या डिक्शनरी लुकअप का उपयोग करें।

उत्तर
तो, पता लगाने के लिए एक ही रास्ता कैसे संकलक व्याख्या कोड की दी गई टुकड़ा वास्तव में यह संकलन और उत्पन्न विधानसभा निरीक्षण करने के लिए है। यह नेट में क्या करना इतना मुश्किल नहीं है ... आप का उपयोग रनटाइम के दौरान एक मनमाना स्ट्रिंग संकलन कर सकता है जिससे की तरह सी # संकलक:

private static Type GetTypeByFullNameOrAlias(string typeName) 
{ 
    Type type = Type.GetType(typeName); 

    if (type == null) 
    { 
    using (var provider = new CSharpCodeProvider()) 
    { 
     var compiler = provider.CompileAssemblyFromSource(
     new CompilerParameters 
      {GenerateInMemory = true, GenerateExecutable = false, IncludeDebugInformation = false}, 
     "public class A { public " + typeName + " B; }"); 

     type = ((FieldInfo)compiler.CompiledAssembly.GetType("A").GetMember("B")[0]).FieldType; 
    } 
    } 

    return type; 
} 

हालांकि, इस तकनीक कई कमियां है ... सबसे पहले यह धीमा है। बेशक आप परिणाम को कैश कर सकते हैं और प्रक्रिया को तेज करने के लिए अन्य चालबाजी कर सकते हैं। लेकिन एक और समस्या है, जो कि "if" कथन के अंदर पहुंचने पर हर बार एक पूर्ण असेंबली को संकलित और लोड करता है। प्रत्येक असेंबली जो इसे लोड करती है उसे फिर से लोड नहीं किया जा सकता है और एप्लिकेशन बंद होने तक चारों ओर लटका होगा, इसलिए यह तकनीक भी स्मृति की एक छोटी राशि को रिसाव कर देगी। दोबारा, आप जेनरेटेड असेंबली को एक अलग ऐपडोमेन में लोड कर सकते हैं और टाइप का निरीक्षण करने के बाद डोमेन को अनलोड कर सकते हैं लेकिन इससे कोड बहुत धीमा हो जाएगा।

लेकिन जैसा कि मैंने शुरुआत में अनुरोध किया था, बस अपने उत्पादन कोड में "स्विच" समाधान का उपयोग करें ... यह उपनामों का अनुवाद करने का एक अच्छा काम है। और ऐसा नहीं है कि वे जल्द ही उन भाषा उपनामों को बदलने जा रहे हैं।

+0

मुझे नहीं पता कि लोग क्यों हैं जब वे संदर्भ नहीं जानते हैं तो प्रदर्शन के बारे में मेरी तरफ से चिंतित है, लेकिन यह सबसे अच्छा है जवाब। निरर्थक प्रकारों को टाइप उपनामों की संख्या दोगुनी हो गई, और यह कोड बच गया होगा जबकि एक स्विच स्टेटमेंट नहीं होगा। धन्यवाद। –

+0

के लिए उन रुचि रखते हैं, आदेश typeAsString का एक उचित राउंड ट्रिप प्राप्त करने के लिए -> typeObject -> typeAsString, यदि आप ऐसा करने की जरूरत है: provider.GetTypeOutput (नई CodeTypeReference (प्रकार)) अन्यथा, नल प्रकार इस तरह के पूर्णांक के रूप में? "System.Nullable'1" में बदलने का प्रयास करें। –

+0

मुझे उम्मीद है कि ऐसा कुछ ऐसा कभी भी उत्पादन कोड तक नहीं पहुंचता है। – ChaosPandion

2

सिस्टम। स्ट्रिंग प्रकार का नाम है, 'स्ट्रिंग' एक उपनाम है। निम्नलिखित कोड मेरे लिए काम करता है, तो शायद मैं आपके उपयोग के मामले नहीं मिलता है:

string s = ""; 
Type t = Type.GetType(s.GetType().ToString()); 
Console.WriteLine(t); // prints "System.String" 

... जो निश्चित रूप से पूरी तरह से बेमानी है के रूप में आप सिर्फ 'एस' अपने प्रकार के लिए पूछ सकते :)

संपादित करें: नीचे टिप्पणी देखने के बाद, आप बस एक स्विच बनाने के लिए आवश्यकता हो सकती है। समस्या यह है कि Type.GetType() पूरी तरह से योग्य नाम चाहता है, और (कुछ खोज के बाद) मैं एक तरह से अपने प्रकार नाम के एक अन्य नाम से मिलान करने नहीं पा सके है। किसी को उस लगता है करता है, भयानक है, लेकिन कुछ इस तरह काफी अच्छी तरह से काम करेगा:

switch (userType) 
{ 
    case "string": return "System.String"; 
    case "sbyte": return "System.SByte"; 
    case "byte": return "System.Byte"; 
    case "short": return "System.Int16"; 
    case "ushort": return "System.UInt16"; 
    case "int": return "System.Int32"; 
    case "uint": return "System.UInt32"; 
    case "long": return "System.Int64"; 
    case "ulong": return "System.UInt64"; 
    case "char": return "System.Char"; 
    case "float": return "System.Single"; 
    case "double": return "System.Double"; 
    case "bool": return "System.Boolean"; 
    case "decimal": return "System.Decimal"; 
    case "void": return "System.Void"; 
    case "object": return "System.Object"; 
    default: return userType; 
} 
+0

मुझे लगता है कि वह टाइप करना चाहता है, "स्ट्रिंग" या "int" टेक्स्ट टाइप करने के लिए टाइप करें (System.String) और टाइपऑफ (System.Int32)। अर्थात। उसके पास * ए * स्ट्रिंग या int नहीं है, उसके पास * नाम * "स्ट्रिंग" या "int" है। – itowlson

+1

लेकिन यह कभी काम नहीं करेगा क्योंकि आपको पूरी तरह से योग्य नाम में प्रवेश करने की आवश्यकता है। –

+0

आपका 'मामला "int" 'में एक समापन उद्धरण गुम है, और आप अनावश्यक' रिटर्न "शून्य को हटा सकते हैं और' फॉल-थ्रू का लाभ उठा सकते हैं। साथ ही, मुझे नहीं पता कि प्रदर्शन कैसे प्रभावित होगा (मुझे लगता है कि यह प्रभावित होगा), लेकिन 'डबल.गेट टाइप()। ToString()' जैसे कुछ का उपयोग करना शायद अधिक सुरुचिपूर्ण और बग-प्रतिरोधी होगा। लेकिन यह व्यक्तिगत वरीयता है, आईएमओ। – mgbowen

2

string, int, और हर दूसरे कीवर्ड सिर्फ इतना है कि है: एक कीवर्ड। यह केवल String या Int32 या Double हर समय लेखन के लिए एक शॉर्टकट है। आपको बस अपने पूर्ण योग्य नामों का उपयोग करना होगा, लेकिन मुझे नहीं पता कि आप अपने पूर्ण नामों का उपयोग करने का विरोध क्यों कर रहे हैं, न कि उनके कीवर्ड।

एक ही रास्ता मैं मानचित्रण खोजशब्दों के देखने के पूरी तरह से योग्य नामों बस एक switch बयान होगा। ऐसी कोई विधि नहीं है जिसके बारे में मुझे पता है कि आप जो भी पूछ रहे हैं वह करेंगे।

+0

यदि आपको वास्तव में इस कार्यक्षमता की आवश्यकता है, तो ऐसा लगता है कि 'स्विच' कथन इतना बुरा नहीं होगा कि मैपिंग पहले से मौजूद है। यह सबसे साफ दृष्टिकोण होगा (और शायद केवल)। +1 – jheddings

+0

मैं उनके पूर्ण नामों का उपयोग करने का विरोध नहीं कर रहा हूं। लेकिन, मुझे यह चुनने की ज़रूरत नहीं है कि नाम OfTheType के लिए क्या पारित किया गया है। मुझे बस काम करने की ज़रूरत है। –

-1

टाइप नाम स्ट्रिंग कहीं से निकल रहे हैं, और यदि कहीं भी टाइप क्लास की FullName प्रॉपर्टी का उपयोग करके निम्न प्रकार में टाइप नाम स्ट्रिंग बनाने के लिए मजबूर किया जा सकता है, तो आपको छोटा फॉर्म नहीं मिलेगा संकेत समस्याग्रस्त है:

string obj = ""; // using obj as an example - could be of any data type 
string bestTypeName = obj.GetType().FullName; // produces "System.String" 
+0

आपको उसमें से कोई भी करने की ज़रूरत नहीं है, obj.GetType.ToString() में गुजरना एक ही प्रभाव होगा। उपयोगकर्ता स्ट्रिंग अक्षर "int" लेना चाहता है और एक टाइप ऑब्जेक्ट प्राप्त करना चाहता है जो System.Int32 से मेल खाता है। मुझे एक ही भ्रम था। –

+0

इसके अलावा उपयोगकर्ता ने पूछा कि क्या "यह सब एक साथ करने का एक बेहतर तरीका है" और इस तरह मैंने जवाब देने का फैसला किया। –

+0

लेकिन यह समस्या का समाधान नहीं कर रहा है। बेशक "" .GetType.FullName सही नाम देता है, लेकिन ओपी के पास काम करने के लिए एक प्रकार का ऑब्जेक्ट नहीं है, उनके पास एक स्ट्रिंग है। –

4

आप CodeDom इस्तेमाल कर सकते हैं एक CodeVariableDeclarationStatement बनाने के लिए, और प्रकार संपत्ति को पुनः प्राप्त:

var stmt = new CodeVariableDeclarationStatement("string", "test"); 
string systemTypeName = stmt.Type.BaseType; 

मुझे यकीन है कि है कि क्या आप CodeDom वर्गों है कि स्वतंत्र रूप से उपयोग कर सकते हैं नहीं हूँ, लेकिन यह स्विच का उपयोग कर एक देखने समारोह को बनाए बिना "System.String" को "स्ट्रिंग" से प्राप्त करने के लिए एक आसान तरीका होना चाहिए।

संपादित करें:

var systemTypeName = new CodeTypeReference("string").BaseType; 

CodeVariableDeclarationStatement.Type संपत्ति एक CodeTypeReference है:

इसके बारे में अधिक सोच रही थी, यह संभव बस सीधे एक CodeTypeReference उपयोग करने के लिए, और इसके बाद के संस्करण की प्रक्रिया शॉर्टकट हो सकता है।सीधे CodeTypeReference का उपयोग करके, आपको डमी चर नाम से परेशान करने की आवश्यकता नहीं है, और यह एक-लाइनर बन सकता है।

काम उदाहरण:

मैं कोड है कि इस पहले किया था पाया। यह थोड़ा और अधिक जटिल की तुलना में मैं आशा व्यक्त की थी, लेकिन यह काम किया जाता है, और अगर उत्पन्न वर्गों कैश नहीं किया जाता, प्रदर्शन प्रारंभिक संकलन के बाद अच्छा है:

using System; 
using System.CodeDom; 
using System.Collections.Generic; 
using System.CodeDom.Compiler; 

using Microsoft.CSharp; 
using System.Diagnostics; 

namespace ConsoleApplication1 
{ 
    public interface IDynamicTypeNameMapper 
    { 
     string GetTypeName(); 
    } 

    class Program 
    { 
     static readonly string[] csharpKeywords = new[] 
     { 
      "byte", 
      "short", 
      "int", 
      "long", 
      "float", 
      "double", 
      "string" 
     }; 

     static Dictionary<string, IDynamicTypeNameMapper> s_mappers; 

     static void Main(string[] args) 
     { 
      s_mappers = new Dictionary<string, IDynamicTypeNameMapper>(); 

      var provider = new CSharpCodeProvider(); 
      var options = new CompilerParameters(); 
      options.ReferencedAssemblies.Add("ConsoleApplication1.exe"); 
      options.GenerateInMemory = true; 

      var stopwatch = new Stopwatch(); 
      stopwatch.Start(); 
      foreach (string keyword in csharpKeywords) 
      { 
       string className = "DynamicTypeNameMapper_" + keyword; 
       string literal = "using System; using ConsoleApplication1; namespace Test { public class " + className + ": IDynamicTypeNameMapper { public string GetTypeName() { return typeof(" + keyword + ").FullName; } } }"; 
       var snippet = new CodeSnippetCompileUnit(literal); 

       var results = provider.CompileAssemblyFromDom(options, snippet); 

       var typeNameMapper = results.CompiledAssembly.CreateInstance("Test." + className) as IDynamicTypeNameMapper; 
       if (typeNameMapper != null) 
       { 
        s_mappers.Add(keyword, typeNameMapper); 
        Console.WriteLine(typeNameMapper.GetTypeName()); 
       } 
      } 
      stopwatch.Stop(); 
      Console.WriteLine("Inital time: " + stopwatch.Elapsed.ToString()); 

      stopwatch.Reset(); 
      stopwatch.Start(); 

      for (int i = 0; i < 1000; i++) 
      { 
       foreach (string keyword in csharpKeywords) 
       { 
        s_mappers[keyword].GetTypeName(); 
       } 
      } 
      stopwatch.Stop(); 

      Console.WriteLine("Cached time: " + stopwatch.Elapsed.ToString()); 

      Console.ReadLine(); 
     } 
    } 
} 

इस प्रकार इस एप्लिकेशन का उत्पादन किया जाता है के रूप में:

System.Byte 
System.Int16 
System.Int32 
System.Int64 
System.Single 
System.Double 
System.String 
Inital time: 00:00:00.3090559 
Cached time: 00:00:00.0011934 
+0

बहुत छोटा और चालाक। उपयोगकर्ता को प्रकार के स्विच स्टेटमेंट को बनाए रखने की आवश्यकता नहीं होती है और यदि माइक्रोसॉफ्ट किसी भी कारण से डेटा प्रकार के सी # का विस्तार करना चाहता है तो यह स्वचालित रूप से काम करेगा। –

+0

कम से कम आशा है कि। : पी मेरे पास अभी तक इसका परीक्षण करने का समय नहीं है ... – jrista

+1

यह काम नहीं करता है: दोनों स्थितियों में, सिस्टम टाइप नाम .NET 3.5 पर केवल "स्ट्रिंग" का मूल्यांकन करता है। उस ने कहा, कोडडॉम के साथ इस काम को करने का एक तरीका होना चाहिए, लेकिन आपको शायद CSharpCodeProvider का उपयोग करने की आवश्यकता होगी, क्योंकि रन-टाइम केवल आईएल बोलता है। – Gabriel

1
static readonly Dictionary<String, String> types = new Dictionary<String, String>() 
{ 
    { "string", "System.String" }, 
    { "sbyte", "System.SByte" }, 
    { "byte", "System.Byte" }, 
    { "short", "System.Int16" }, 
    { "ushort", "System.UInt16" }, 
    { "int", "System.Int32" }, 
    { "uint", "System.UInt32" }, 
    { "long", "System.Int64" }, 
    { "ulong", "System.UInt64" }, 
    { "char", "System.Char" }, 
    { "float", "System.Single" }, 
    { "double", "System.Double" }, 
    { "bool", "System.Boolean" }, 
    { "decimal", "System.Decimal" }, 
    { "void", "System.Void" }, 
    { "object", "System.Object" } 
}; 

private void Execute(String user_type) 
{ 
    String type; 
    if (!types.TryGetValue(user_type, out type)) 
    { 
     type = user_type; 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे