2009-05-15 26 views
9

क्या यह देखना संभव है कि कौन सा कन्स्ट्रक्टर सामान्य था?जेनेरिक कन्स्ट्रक्टर और प्रतिबिंब

internal class Foo<T> 
{ 
    public Foo(T value) {} 
    public Foo(string value) {} 
} 

var constructors = typeof(Foo<string>).GetConstructors(); 

संपत्ति 'कंटेनस जेनरिक पैरामीटर' दोनों मुझे रचनाकारों के लिए झूठी रिटर्न देता है। क्या यह पता लगाने का कोई तरीका है कि रचनाकार [0] सामान्य है? दोनों के पास एक ही हस्ताक्षर है, लेकिन मैं "वास्तविक" स्ट्रिंग को कॉल करना चाहता हूं।

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

मैं दिया प्रकार का उपयोग

ilGen.Emit(OpCodes.Newobj, constructorInfo); 

तो मैं बाध्य संस्करण के साथ काम करने की जरूरत आह्वान करने के लिए चाहते हैं। लेकिन मैं "सर्वश्रेष्ठ" कन्स्ट्रक्टर का आह्वान करना चाहता हूं। यह मानक व्यवहार होना चाहिए। जब मैं

new Foo<string>() 

निर्माता फोन स्ट्रिंग हस्ताक्षर (और नहीं सामान्य हस्ताक्षर के साथ एक) के साथ कहा जाता है। मेरे कोड के साथ भी ऐसा ही होना चाहिए।

उत्तर

8

आप सिस्टम चाहते हैं। रिफ्लेक्शन। पैरामीटर इंफो। पैरामीटर टाइप। आईजेनरिक पैरामीटर। यहाँ एक VS2008 इकाई परीक्षण है कि गुजरता है कि इस दिखाता है:

कक्षा:

public class Foo<T> 
{ 
    public Foo(T val) 
    { 
     this.Value = val.ToString(); 
    } 
    public Foo(string val) 
    { 
     this.Value = "--" + val + "--"; 
    } 

    public string Value { get; set; } 
} 

टेस्ट विधि:

Foo<string> f = new Foo<string>("hello"); 
Assert.AreEqual("--hello--", f.Value); 

Foo<int> g = new Foo<int>(10); 
Assert.AreEqual("10", g.Value); 

Type t = typeof(Foo<string>); 
t = t.GetGenericTypeDefinition(); 

Assert.AreEqual(2, t.GetConstructors().Length); 

System.Reflection.ConstructorInfo c = t.GetConstructors()[0]; 
System.Reflection.ParameterInfo[] parms = c.GetParameters(); 
Assert.AreEqual(1, parms.Length); 
Assert.IsTrue(parms[0].ParameterType.IsGenericParameter); 

c = t.GetConstructors()[1]; 
parms = c.GetParameters(); 
Assert.AreEqual(1, parms.Length); 
Assert.IsFalse(parms[0].ParameterType.IsGenericParameter); 

यहाँ उल्लेखनीय बात parms [0] जाँच .ParameterType.IsGenericParameter है जो जांचता है कि पैरामीटर एक सामान्य है या नहीं।

एक बार जब आप अपना कंस्ट्रक्टर पा लेते हैं तो आपको एमिट पास करने के लिए कन्स्ट्रक्टर इंफो मिल गया है।

public System.Reflection.ConstructorInfo FindStringConstructor(Type t) 
{ 
    Type t2 = t.GetGenericTypeDefinition(); 

    System.Reflection.ConstructorInfo[] cs = t2.GetConstructors(); 
    for (int i = 0; i < cs.Length; i++) 
    { 
     if (cs[i].GetParameters()[0].ParameterType == typeof(string)) 
     { 
      return t.GetConstructors()[i]; 
     } 
    } 

    return null; 
} 

नहीं बिल्कुल यकीन है कि क्या आपका इरादा हालांकि है।

+0

आपके उत्तर के लिए धन्यवाद - यहां समस्या यह है कि आप "टाइप टी = टाइपोफ (फू <>);" - यह अब टाइप नहीं करेगा "टाइप टी = टाइपोफ (फू );" – tanascius

+0

इसे Foo <> पर प्राप्त करने के लिए GetGenericTypeDefinition() पर कॉल करें, फिर कन्स्ट्रक्टर इंडेक्स अभी भी उसी कन्स्ट्रक्टर को मैप करें। तो आप सही इंडेक्स को खोजने के लिए Foo <> .. ctor पर प्रतिबिंबित कर सकते हैं, फिर अपने आईएल जनरेटर से मिलान Foo ..क्टर का उपयोग करें। जहां तक ​​मैं आपको बता सकता हूं कि जब आप Foo के साथ जाते हैं तो आप सभी जेनेरिक-नेस खो देते हैं। –

+2

GetGenericTypeDefinition() बिल्कुल वही था जो मैंने याद किया था। आपका बहुत बहुत धन्यवाद! – tanascius

0

आप Type.GetGenericArguments परिणाम प्रकार (ओं) की जांच कर सकते हैं, और इसकी तुलना कन्स्ट्रक्टर पैरामीटर प्रकार से कर सकते हैं।

बस एक ऐसे प्रकार के साथ कॉल करें जो समान नहीं है (प्रकार! = टाइपोफ (टी))।

+0

दुर्भाग्य से यह मेरी समस्या के लिए काम नहीं कर रहा है। मैं टाइपफ (फू ) का उपयोग कर रहा हूं - GetGenericArguments() का परिणाम स्ट्रिंग होगा ... मेरे दोनों रचनाकार मुझे बताते हैं कि वे एक स्ट्रिंग मान ले रहे हैं - लेकिन कौन सा सामान्य है? – tanascius

+0

न तो सामान्य है क्योंकि आपने प्रकार तर्क के रूप में स्ट्रिंग प्रदान करके प्रकार को बंद कर दिया है। इसके बजाय टाइपफ (Foo <>) का उपयोग करें। – x0n

2

थोड़ा स्पष्टीकरण। रचनाकारों में से कोई भी सामान्य तरीकों नहीं हैं। वे एक सामान्य वर्ग पर सामान्य तरीके हैं। "जेनेरिक" होने की विधि के लिए इसमें एक सामान्य पैरामीटर होना चाहिए। तो "IsGenericMethod" जैसे परीक्षण करना झूठा होगा।

पैरामीटर को देखने और यह निर्धारित करना भी आसान नहीं है कि वे सामान्य हैं या नहीं। नमूने के लिए आपने तर्कों को चलना और सामान्य पैरामीटर की तलाश करना संभव है। लेकिन निम्नलिखित कोड

public Foo(IEnumerable<T> p1) ... 
public Foo(IEnumerable<KeyValuePair<string,Func<T>>> p1) ... 

आपको इस तरह की वस्तुओं को ध्यान में रखना होगा।

संपादित

कारण आप सभी तर्कों को देख रहे हैं के रूप में स्ट्रिंग है, क्योंकि आप स्पष्ट रूप कंस्ट्रक्टर होने से पहले प्रकार फू बाध्य। अपने कोड को निम्नलिखित में स्विच करने का प्रयास करें जो एक अनबाउंड फू का उपयोग करता है और इसलिए विधियों में जेनेरिक पैरामीटर लौटाएगा।

var constructors = typeof(Foo<>).GetConstructors(); 
+0

"नमूने के लिए आपने तर्कों को चलना और सामान्य पैरामीटर की तलाश करना संभव है।" - यही सवाल है ... मैं अभी भी यह कैसे करना है इसके बारे में अनिश्चित हूं। सभी तर्क स्ट्रिंग प्रतीत होते हैं - जेनेरिक-नेस – tanascius

+0

@tanascius का कोई संकेत नहीं, बस मेरी व्याख्या और स्पष्टीकरण के लिए समस्या – JaredPar

+0

धन्यवाद। मुझे पता है, यह टाइपफॉफ़ (फू <>) के साथ काम करता है ... तो क्या मैं आपको सही ढंग से समझता हूं, कि स्ट्रिंग प्रतिबिंब के बाध्यकारी के बाद अब मेरी मदद नहीं होगी? – tanascius

0

आप अधिक आप क्या हासिल करने की कोशिश कर रहे हैं एक बिट की व्याख्या कर सकते हैं जब आप कहते हैं कि तुम ठोस निर्माता कॉल करना चाहते हैं? मैं केवल उत्सुक हूं कि यह पता लगाने के बिना कि आपके निर्माता को सामान्य पैरामीटर शामिल हैं या नहीं, आपके मुद्दे को हल करने का कोई और तरीका है।

मैं चेनिंग कंस्ट्रक्टर्स या इमारत तर्क सोच रहा हूँ सामान्य से एक में एक निश्चित तरीके से व्यवहार करने के लिए करता है, तो पैरामीटर में पारित कर दिया जैसे एक स्ट्रिंग है,:

static void Main(string[] args) 
    { 
     Console.WriteLine(new Foo<string>("myValue").IsValueAString); 
     Console.WriteLine(new Foo<int>(1).IsValueAString); 
     Console.ReadLine(); 
    } 

    public class Foo<T> 
    { 
     public bool IsValueAString = false; 
     public Foo(T value) { 
      if (value is string) 
      { 
       IsValueAString = true; 
      } 
     } 
    } 

एक अन्य विकल्प एक ठोस कार्यान्वयन के लिए किया जाएगा फू, जैसे कुछ:

internal class Foo<T> 
{ 
    ... 
} 
internal class MyFoo : Foo<string> 
{ 
    ... 
} 

और वंश के निर्माता में कोई विशिष्ट तर्क एम्बेड करें।इस पथ के नीचे सभी प्रकार के विकल्प संभव हैं ताकि आप उस वर्ग से जानकारी को प्रतिबिंबित करने से बच सकें।

+0

मेरा संपादन देखें। मैं एक सामान्य प्रकार का आह्वान करना चाहता हूं - दुर्भाग्य से मैं प्राप्त प्रकार को संशोधित नहीं कर सकता। मुझे काम करना चाहिए सभी प्रकार के सामान्य प्रकार। – tanascius

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