2008-12-30 26 views
25

मैं कोड पीढ़ी पर काम कर रहा हूं और जेनेरिक के साथ एक झगड़ा में भाग गया। मुझे एक समस्या का कारण बनने का एक "सरलीकृत" संस्करण यहां दिया गया है।प्रतिबिंब का उपयोग करके जेनेरिक प्रकार की सही टेक्स्ट परिभाषा कैसे प्राप्त कर सकता हूं?

Dictionary<string, DateTime> dictionary = new Dictionary<string, DateTime>(); 
string text = dictionary.GetType().FullName; 
ऊपर कोड के साथ

झलकी text का मूल्य इस प्रकार है: (। लाइन ब्रेक बेहतर पठनीयता के लिए जोड़ा)

System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.DateTime, mscorlib, 
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] 

वहाँ एक रास्ता प्रकार का नाम (प्राप्त करने के लिए है type) उपर्युक्त स्ट्रिंग को पार्स किए बिना एक अलग प्रारूप में? मैं text के लिए इच्छा निम्न परिणाम:

System.Collections.Generic.Dictionary<System.String, System.DateTime> 
+2

ध्यान दें कि अगर आप .FullName' हटाने 'और' का उपयोग .ToString() 'बजाय, आप मिल" पाठ "' 'System.Collections.Generic.Dictionary'2 [System.String, System.DateTime] '' जो अधिक पठनीय है, और जो आप चाहते हैं उसके करीब है। –

उत्तर

27

कोई अंतर्निहित तरीका नेट फ्रेमवर्क में इस प्रतिनिधित्व प्राप्त करने के लिए नहीं है। अर्थात् क्योंकि इसे सही करने का कोई तरीका नहीं है। वहां बड़ी संख्या में संरचनाएं हैं जो सी # शैली वाक्यविन्यास में प्रतिनिधित्व योग्य नहीं हैं। उदाहरण के लिए "<> foo" आईएल में एक वैध प्रकार का नाम है लेकिन सी # में प्रदर्शित नहीं किया जा सकता है।

हालांकि, यदि आप एक बहुत अच्छे समाधान की तलाश में हैं तो इसे हाथ से काफी जल्दी लागू किया जा सकता है। नीचे का समाधान ज्यादातर स्थितियों के लिए काम करेगा। यह

  1. नेस्टेड प्रकार संभाल नहीं होगा
  2. अवैध सी # नाम
  3. अन्य परिदृश्यों की
  4. युगल

उदाहरण:

public static string GetFriendlyTypeName(Type type) { 
    if (type.IsGenericParameter) 
    { 
     return type.Name; 
    } 

    if (!type.IsGenericType) 
    { 
     return type.FullName; 
    } 

    var builder = new System.Text.StringBuilder(); 
    var name = type.Name; 
    var index = name.IndexOf("`"); 
    builder.AppendFormat("{0}.{1}", type.Namespace, name.Substring(0, index)); 
    builder.Append('<'); 
    var first = true; 
    foreach (var arg in type.GetGenericArguments()) 
    { 
     if (!first) 
     { 
      builder.Append(','); 
     } 
     builder.Append(GetFriendlyTypeName(arg)); 
     first = false; 
    } 
    builder.Append('>'); 
    return builder.ToString(); 
} 
+0

ऊपर और परे! यह पूरी तरह से काम करता है! धन्यवाद!! –

+0

यदि आपको कोई मौका मिलता है तो अपना जवाब संपादित करें और "स्थिर स्ट्रिंग GetFriendlyTypeName (टाइप प्रकार) {if (type.IsGenericParameter) {return type.Name;}" कोड ब्लॉक में :) –

+0

@Jamey, किया गया। यह वास्तव में बहुत अजीब है। जब तक मैं आदेशित सूची और ब्लॉक की शुरुआत के बीच एक गैर कोड कोड जोड़ता हूं तब तक कोड ब्लॉक पहली पंक्ति नहीं जोड़ता। – JaredPar

0

मुझे नहीं लगता कि नेट में अंतर्निहित कुछ भी है कि इस करना होगा, ताकि आप इसे अपने आप को क्या करना होगा। मुझे लगता है कि प्रतिबिंब वर्ग इस रूप में प्रकार के नाम का पुनर्निर्माण करने के लिए पर्याप्त जानकारी प्रदान करते हैं।

+0

मैंने इस मार्ग को आजमाया है कि आप समाधान पर विस्तार कर सकते हैं? मुझे गुण या संग्रह नहीं मिला है जो मुझे यह जानकारी देते हैं जिसका उपयोग मैं घोषणा के पुनर्निर्माण के लिए कर सकता हूं। –

0

मैं, लगता है कि आप

System.String, mscorlib पारित कर सकते हैं संस्करण = 2.0.0.0, संस्कृति = तटस्थ, PublicKeyToken = b77a5c561934e089

Type.Parse() में

। यह एक पूरी तरह से योग्य प्रकार का नाम है, मुझे लगता है।

+0

आवश्यक नहीं है। मूल शब्दकोश। गेटटाइप() में पहले से ही टाइप पैरामीटर का संग्रह शामिल है जिसे आप सीधे एक्सेस कर सकते हैं। एक ही परिणाम प्राप्त करने के लिए पार्सिंग की कोई ज़रूरत नहीं है। –

2
string text = dictionary.ToString(); 

आप के लिए लगभग क्या पूछ रहे हैं प्रदान करता है:

System.Collections.Generic.Dictionary`2[System.String,System.DateTime] 
+0

हालांकि यह एक सामान्य समाधान नहीं है। कोई भी प्रकार जो उपयोग करता है। ToString() इस समाधान को तोड़ देगा – JaredPar

+0

@ जेरेडपार जिसे 'dictionary.GetType()। ToString()' का उपयोग करके हल किया जाता है। –

4

आज शाम मैं विस्तार तरीकों के साथ एक सा कर रही थी और मैंने आपके प्रश्न का उत्तर खोजने की कोशिश की। परिणाम यहां दिया गया है: यह कोई वारंटी कोड नहीं है। ;-)

internal static class TypeHelper 
{ 
    private const char genericSpecialChar = '`'; 
    private const string genericSeparator = ", "; 

    public static string GetCleanName(this Type t) 
    { 
     string name = t.Name; 
     if (t.IsGenericType) 
     { 
      name = name.Remove(name.IndexOf(genericSpecialChar)); 
     } 
     return name; 
    } 

    public static string GetCodeDefinition(this Type t) 
    { 
     StringBuilder sb = new StringBuilder(); 
     sb.AppendFormat("{0}.{1}", t.Namespace, t.GetCleanName()); 
     if (t.IsGenericType) 
     { 
      var names = from ga in t.GetGenericArguments() 
         select GetCodeDefinition(ga); 
      sb.Append("<"); 
      sb.Append(string.Join(genericSeparator, names.ToArray())); 
      sb.Append(">"); 
     } 
     return sb.ToString(); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     object[] testCases = { 
           new Dictionary<string, DateTime>(), 
           new List<int>(), 
           new List<List<int>>(), 
           0 
          }; 
     Type t = testCases[0].GetType(); 
     string text = t.GetCodeDefinition(); 
     Console.WriteLine(text); 
    } 
} 
+0

धन्यवाद! यह समाधान भी काम करता है। –

19

एक अच्छा और साफ विकल्प, @LukeH's comment करने के लिए धन्यवाद, है

using System; 
using System.CodeDom; 
using System.Collections.Generic; 
using Microsoft.CSharp; 
//... 
private string GetFriendlyTypeName(Type type) 
{ 
    using (var p = new CSharpCodeProvider()) 
    { 
     var r = new CodeTypeReference(type); 
     return p.GetTypeOutput(r); 
    } 
} 
+3

उत्तर के रूप में चिह्नित होने के बाद बहुत बेहतर (सामान्य वर्गों के उप-वर्ग सही ढंग से दिखाए जाते हैं) – FLCL

+2

इससे कोई प्रदर्शन प्रभाव? –

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

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