की जेनिक्स, विरासत, और असफल विधि संकल्प आज मैं एक संकलन मुद्दे में भाग गया जो मुझे परेशान करता था। इन दो कंटेनर वर्गों पर विचार करें।सी # कंपाइलर
public class BaseContainer<T> : IEnumerable<T>
{
public void DoStuff(T item) { throw new NotImplementedException(); }
public IEnumerator<T> GetEnumerator() { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { }
}
public class Container<T> : BaseContainer<T>
{
public void DoStuff(IEnumerable<T> collection) { }
public void DoStuff <Tother>(IEnumerable<Tother> collection)
where Tother: T
{
}
}
पूर्व परिभाषित करता है DoStuff(T item)
और DoStuff <Tother>(IEnumerable<Tother>)
विशेष रूप से के साथ बाद भार के यह सी # के covariance/contravariance के अभाव के आसपास पाने के लिए (4 जब तक मैंने सुना है)।
इस कोड
Container<string> c = new Container<string>();
c.DoStuff("Hello World");
एक नहीं बल्कि अजीब संकलन त्रुटि पूरी करता है। विधि कॉल से <char>
की अनुपस्थिति पर ध्यान दें।
प्रकार 'चार' सामान्य प्रकार या विधि 'Container.DoStuff (System.Collections.Generic.IEnumerable)' के रूप में प्रकार पैरामीटर 'Tother' नहीं किया जा सकता। 'Char' से 'string' तक कोई मुक्केबाजी रूपांतरण नहीं है।
अनिवार्य रूप से, संकलक Container.DoStuff<char>(IEnumerable<char>)
क्योंकि string
औजार IEnumerable<char>
में DoStuff(string)
करने के लिए अपने कॉल जाम करने के बजाय BaseContainer.DoStuff(string)
का उपयोग कर रहा है।
एक ही रास्ता है कि मैं इस संकलन बनाने के लिए मिल गया है व्युत्पन्न वर्ग के लिए DoStuff(T)
जोड़ना है
public class Container<T> : BaseContainer<T>
{
public new void DoStuff(T item) { base.DoStuff(item); }
public void DoStuff(IEnumerable<T> collection) { }
public void DoStuff <Tother>(IEnumerable<Tother> collection)
where Tother: T
{
}
}
क्यों संकलक IEnumerable<char>
के रूप में एक स्ट्रिंग जाम करने जब 1) यह जानता है कि यह कर सकते हैं 'कोशिश कर रहा है टी (संकलन त्रुटि की उपस्थिति को देखते हुए) और 2) इसमें बेस क्लास में एक विधि है जो ठीक से संकलित करती है? क्या मैं सी # में जेनेरिक या वर्चुअल विधि सामग्री के बारे में कुछ गलत समझ रहा हूं? क्या new DoStuff(T item)
से Container
जोड़ने के अलावा कोई अन्य फ़िक्स है?
का उपयोग कर मैं मानता हूँ यह अजीब लगता है, लेकिन यह कल्पना के अनुसार सही है। यह दो नियमों की बातचीत का एक परिणाम है: (1) ओवरलोड रिज़ॉल्यूशन प्रयोज्यता जांच बाध्यता जांच से पहले होती है, और (2) व्युत्पन्न कक्षाओं में लागू विधियां बेस कक्षाओं में लागू विधियों से हमेशा बेहतर होती हैं। दोनों उचित समझदार नियम हैं; वे सिर्फ आपके मामले में विशेष रूप से बुरी तरह से बातचीत करते हैं। –
विवरण के लिए खंड 7.5.5.1 देखें, विशेष रूप से बिट्स जो कहते हैं: (1) "यदि सबसे अच्छी विधि एक सामान्य विधि है, तो टाइप तर्क (आपूर्ति या अनुमानित) बाधाओं के खिलाफ चेक किए जाते हैं ..." और (2) " उम्मीदवार विधियों का सेट कम से कम व्युत्पन्न प्रकारों से केवल विधियों को कम करने के लिए कम किया गया है ... " –
अंततः आपकी समस्या एक डिज़ाइन समस्या है। आप "DoStuff" विधि को ओवरलोड कर रहे हैं, जिसका अर्थ है "टाइप टी के एक ही मान पर सामान करें" और "टाइप टी के मानों के अनुक्रम में सामान करें"। यह कई तरीकों से गंभीर "इरादा संकल्प" समस्याओं में चलता है - उदाहरण के लिए, जब "टाइप टी" स्वयं एक अनुक्रम होता है। आप पाएंगे कि बीसीएल में मौजूदा संग्रह कक्षाओं को इस समस्या से बचने के लिए सावधानीपूर्वक डिजाइन किया गया है; किसी आइटम को लेने वाली विधियों को "फ्रोब" कहा जाता है, वस्तुओं के अनुक्रम को लेने वाले विधियों को "FrobRange" कहा जाता है, उदाहरण के लिए सूचियों पर "जोड़ें" और "AddRange" कहा जाता है। –