2013-09-03 7 views
6

मैं कुछ विस्तार तरीकों कि एक अभिव्यक्ति पैरामीटर का उपयोग एक संपत्ति सदस्य है और इस पर कार्य में खींचने के लिए है, और मुझे विशेष मामले के लिए एक अधिभार जहां सदस्य एक IEnumerable है <>। हालांकि, से नीचे आर 4 के लिए जेनेरिक क्लास () के अंदर से कॉल किए जाने पर अपेक्षित विधि अधिभार से मेल नहीं लगता है। कक्षा के बाहर सही विधि का चयन किया जाता है।एक्सटेंशन विधि चयन सामान्य प्रकार और का उपयोग कर भाव

यहां क्या हो रहा है? क्या यह कभी काम करेगा या मुझे एक नया दृष्टिकोण खोजने की ज़रूरत है?

public class Test 
{ 
    public void MyTest() 
    { 
     // returns "Object" 
     var r1 = new MyClass<object>().Ext(a => a.Content); 

     // returns "Enumerable" 
     var r2 = new MyClass<IEnumerable<object>>().Ext(a => a.Content); 

     // returns "Object" 
     var r3 = new MyClass<object>().TestExt(); 

     // returns "Object" (I was expecting "Enumerable") 
     var r4 = new MyClass<IEnumerable<object>>().TestExt(); 

     // returns "Enumerable" 
     var r5 = new MyClass<int>().TestExt2(); 
    } 
} 

public class MyClass<T> 
{ 
    public T Content { get; set; } 

    public IEnumerable<object> OtherContent { get; set; } 

    public string TestExt() 
    { 
     return this.Ext(a => a.Content); 
    } 

    public string TestExt2() 
    { 
     return this.Ext(a => a.OtherContent); 
    } 
} 

public static class MyExtensions 
{ 
    public static string Ext<T>(this T obj, Expression<Func<T, IEnumerable<object>>> memberExpression) 
    { 
     return "Enumerable"; 
    } 

    public static string Ext<T>(this T obj, Expression<Func<T, object>> memberExpression) 
    { 
     return "Object"; 
    } 
} 
+0

यहां क्या गलत है? –

+0

@ किंगिंगकिंग 'आर 4' की घोषणा के बगल में टिप्पणी देखें –

उत्तर

4

जेनेरिक्स गतिशील टाइपिंग नहीं हैं (यह सी # 5 में है)। कॉल करने के लिए कौन सा अधिभार संकलित समय पर जमे हुए है। जब प्रोग्राम बाद में चलाया जाता है, भले ही परिवर्तनीय एक अधिक विशिष्ट रन-टाइम प्रकार धारण करता है, इससे कोई फर्क नहीं पड़ता क्योंकि ओवरलोड को संकलन-समय पर तय किया गया था।

आपका विधि:

public string TestExt() 
{ 
    return this.Ext(a => a.Content); 
} 

Ext में से एक विशिष्ट अधिभार को संकलन समय पर बाध्य करने के लिए है। चूंकि हम T (a.Content का प्रकार) MyClass<T> में जानते हैं कि यह object में कनवर्ट करने योग्य है, इसलिए वास्तव में केवल एक ओवरलोड लोड करने के लिए है, इसलिए यह कंपाइलर के लिए आसान है।

तब से, TestExt विधि निकाय को Ext के उस विशिष्ट अधिभार को कॉल करने के लिए हार्ड-कोड किया गया है।


संपादित करें: यहाँ एक बहुत सरल उदाहरण है:

static void Main() 
{ 
    IEnumerable<object> e = new List<object>(); 
    var r = Generic(e); 
} 

static string Generic<T>(T x) 
{ 
    return Overloaded(x); 
} 

static string Overloaded(IEnumerable<object> x) 
{ 
    return "Enumerable"; 
} 
static string Overloaded(object x) 
{ 
    return "Object"; 
} 

और के रूप में आप अब तक समझते हैं, r"Object" हो जाता है।

(यदि आपने T को किसी भी तरह से बाधित किया है, उदाहरण के लिए where T : IEnumerable<object>, चीजें अलग होंगी)।

यह ऑपरेटरों के लिए भी वही है। उदाहरण के लिए == ऑपरेटर इस अर्थ में ओवरलोड हो गया है कि यह सामान्य संदर्भ प्रकारों के लिए और दूसरे में तारों के लिए एक ही तरीके से काम करता है।

static void Main() 
{ 
    string str1 = "abc"; 
    string str2 = "a"; 
    str2 += "bc";  // makes sure this is a new instance of "abc" 

    bool b1 = str1 == str2;  // true 
    bool b2 = Generic(str1, str2); // false 
} 

static bool Generic<T>(T x, T y) where T : class 
{ 
    return x == y; 
} 

जहां b2 हो जाता है false: तो नीचे दिए गए उदाहरण में, ऑपरेटर == से पहले Overloaded की भूमिका लेता है।

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