2013-05-29 15 views
5

पर कोई विस्तार विधि 'पहला' (बहुत सरल) कोड दिया गया।व्युत्पन्न कक्षा

public class Class1 
{ 
} 

public class Class2 : Class1 
{ 
} 

public class List1 : System.Collections.Generic.IEnumerable<Class1> 
{ 
    public new System.Collections.Generic.IEnumerator<Class1> GetEnumerator() 
    { 
     yield return new Class1();    
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 


public class List2 : List1 , System.Collections.Generic.IEnumerable<Class2> 
{  
    public new System.Collections.Generic.IEnumerator<Class2> GetEnumerator() 
    { 
     yield return new Class2();    
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 

तो कोड

var l = new List2(); 
var first = l.First(); 

संकलन नहीं होगा, लेकिन त्रुटि

'List2' के लिए एक परिभाषा शामिल नहीं है देता है 'प्रथम' और कोई विस्तार विधि 'प्रथम' प्रकार 'सूची 2' के पहले तर्क को स्वीकार करते हुए पाया जा सकता है (क्या आप एक प्रयोग निर्देश या असेंबली संदर्भ खो रहे हैं?)

यदि सूची 2 सूची 1 से प्राप्त नहीं किया गया है तो यह ठीक संकलित करता है, जो साबित करता है कि सूची 2 में वैध एक्सटेंशन विधि है।

क्या यह केवल एक भ्रामक त्रुटि का मामला है और समस्या यह है कि इसमें दो कई एक्सटेंशन विधियां हैं और यह नहीं पता कि कौन से को चुनना है?

यदि ऐसा है, तो यह क्यों नहीं कह सकता कि क्लास 2 विधि के अधिभार रिज़ॉल्यूशन के साथ उपयोग करने के समान ही विशिष्ट संस्करण है?

+3

आप निश्चित रूप से 'सिस्टम का उपयोग कर रहे हैं। लिंक्स;', है ना? –

+0

हां। (अन्यथा यह संकलित नहीं होगा जब List2 सूची 1 से प्राप्त नहीं किया गया है)। – sgmoore

उत्तर

7

समस्या यह है कि List2 लागू करता है दोनों IEnumerable<Class1> और IEnumerable<Class2>, तो संकलक जो Enumerable.First<Class1> या Enumerable.First<Class2> की कॉल करने के लिए पता नहीं है। प्रभावी रूप से, कोई सर्वश्रेष्ठ T नहीं है कि संकलक Enumerable.First<T>(l) का आह्वान कर सकता है, और इसलिए यह किसी भी सामान्य Enumerable.First<T> को योग्य विधि के रूप में नहीं मानता है। इसलिए, अब यह First नामक एक गैर-जेनेरिक विधि के लिए केवल एक पैरामीटर के साथ देख रहा है जो l को स्पष्ट रूप से परिवर्तित किया जा सकता है, और यह कोई भी नहीं मिल सकता है।

आप स्पष्ट हो सकता है और कहते हैं कि

var first = l.First<Class1>(); 

या

var first = l.First<Class2>(); 

और फिर आप ठीक हैं कर सकते हैं।

public class List1 : IEnumerable<string>, IEnumerable<object> 
     { 
      IEnumerator<object> IEnumerable<object>.GetEnumerator() 
      { 
       return GetEnumerator(); 
      } 

      public IEnumerator<string> GetEnumerator() 
      { 
       throw new NotImplementedException(); 
      } 

      IEnumerator IEnumerable.GetEnumerator() 
      { 
       return GetEnumerator(); 
      } 
     } 

तो संकलक पहले पता नहीं है() विधि IEnumerable<string> या IEnumerable<object> की जिनमें से कॉल करने के लिए:

+0

इन दो कॉलों के बीच क्या अंतर है और आप पहले क्या उम्मीद करते हैं। गेट टाइप() दोनों मामलों में वापस आने के लिए? – sgmoore

2

इस वर्ग पर विचार करें। यह उदाहरण आपकी स्थिति का सरलीकृत संस्करण है।

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

+0

अच्छी व्याख्या। – mehrandvd

-1

जेनेरिक तरीकों के साथ समस्या क्या है?

अपनी कक्षा List1 से विरासत और IEnumerable<Class2> से यह वास्तव में 3 प्रकार से इनहेरिट है जब: List1, IEnumerable<Class1> और IEnumerable<Class2> (और object)। इसका मतलब है कि आपकी कक्षा में First<>() के लिए 2 अलग-अलग कार्यान्वयन हैं क्योंकि संकलक "डिफ़ॉल्ट" विधि उत्पन्न नहीं करता है जो कोई सामान्य तर्क नहीं लेता क्योंकि यह पता नहीं लगा सकता कि टी क्या है।

इसका मतलब यह नहीं है कि First<>() उपलब्ध नहीं है, इसका मतलब यह है कि आपको यह निर्दिष्ट करना है कि टी क्या है।

 var l2 = new List2(); 

     l2.First<Class1>(); 
     l2.First<Class2>(); 

दोनों First<Class1>() और First<Class2>() उपलब्ध हैं और तब से संकलक को समझ नहीं सकता T है क्या:

निम्नलिखित कोड का टुकड़ा पर विचार करें।

लेकिन इस कोड स्निपेट में:

l2.First((Class2 c) => c.ToString() == ""); 

संकलक लगा सकते हैं TClass2 तो निम्नलिखित ठीक संकलित कर देगा है।

अच्छा डिजाइन अभ्यास

हालांकि पिछले दृष्टिकोण मान्य है, यह एक वर्ग है कि एक ही इंटरफ़ेस दो बार इनहेरिट करना एक अच्छा डिजाइन प्रथा नहीं है। (आपके मामले में, Class1 के माध्यम से, और IEnumerable<Class2> के स्पष्ट विरासत के माध्यम से दूसरा)। एक बेहतर डिजाइन के लिए आप एक सामान्य अमूर्त वर्ग को लागू कर सकते हैं और अपनी सूचियों को इस वर्ग के रूप में प्राप्त करने के लिए बना सकते हैं।

public abstract class CommonListBase 
{ 

} 

public class List1 : CommonListBase, IEnumerable<Class1> 
{ 
    public System.Collections.Generic.IEnumerator<Class1> GetEnumerator() 
    { 
     yield return new Class1(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 


public class List2 : CommonListBase, IEnumerable<Class2> 
{ 
    public System.Collections.Generic.IEnumerator<Class2> GetEnumerator() 
    { 
     yield return new Class2(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 
संबंधित मुद्दे