C # में जेनेरिक के साथ सहसंयोजक विरोधाभासी समझने में समस्या


115

मैं यह नहीं समझ सकता कि निम्न C # कोड क्यों संकलित नहीं करता है।

जैसा कि आप देख सकते हैं, मेरे पास एक स्टैटिक जेनेरिक तरीका है IEnumerable<T>(पैरामीटर के साथ कुछ और Tएक IAइंटरफेस होने के लिए विवश है ), और इस पैरामीटर को संक्षेप में परिवर्तित नहीं किया जा सकता है IEnumerable<IA>

स्पष्टीकरण क्या है? (मैं वर्कअराउंड के लिए खोज नहीं करता, बस यह समझने के लिए कि यह काम क्यों नहीं करता है)।

public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }

public static class Test
{
    public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
    {
        var bar = foo.ToList();

        // All those calls are legal
        Something2(new List<IA>());
        Something2(new List<IB>());
        Something2(new List<CIA>());
        Something2(new List<CIAD>());
        Something2(new List<CIB>());
        Something2(new List<CIBD>());
        Something2(bar.Cast<IA>());

        // This call is illegal
        Something2(bar);

        return bar;
    }

    private static void Something2(IEnumerable<IA> foo)
    {
    }
}

त्रुटि मुझे Something2(bar)लाइन में मिलती है :

तर्क 1: 'System.Collections.Generic.List' से 'System.Collections.Generic.IEnumerable' में परिवर्तित नहीं हो सकता



12
आपने Tसंदर्भ प्रकारों तक सीमित नहीं रखा है। यदि आप स्थिति का उपयोग करते हैं where T: class, IAतो यह काम करना चाहिए। लिंक किए गए उत्तर में अधिक विवरण हैं।
डिर्क

2
@ मुझे नहीं लगता कि इसे एक डुप्लिकेट के रूप में चिह्नित किया जाना चाहिए। हालांकि यह सच है कि यहां अवधारणा समस्या मूल्य प्रकारों के सामने एक सहसंयोजक / विरोधाभासी समस्या है, यहां विशिष्ट मामला "क्या इस त्रुटि संदेश का अर्थ है" और साथ ही साथ लेखक को "वर्ग" सहित केवल साकार नहीं होने पर उसके मुद्दे को ठीक करता है। मेरा मानना ​​है कि भविष्य के उपयोगकर्ता इस त्रुटि संदेश की खोज करेंगे, इस पोस्ट को खोजें, और खुश रहें। (जैसा कि मैं अक्सर करता हूं।)
रेगिनाल्ड ब्लू

आप Something2(foo);सीधे-सीधे कहकर भी स्थिति को पुन: पेश कर सकते हैं। .ToList()एक पाने के लिए चारों ओर जा रहा है List<T>( Tजेनेरिक विधि द्वारा घोषित आपका प्रकार पैरामीटर है) इस (ए ) को समझने के लिए आवश्यक नहीं List<T>है IEnumerable<T>
जेपी स्टिग नील्सन

@ReginaldBlue 100%, एक ही बात पोस्ट करने जा रहा था। इसी तरह के जवाब एक नकली सवाल नहीं बनाते हैं।
UUDdLrLrSs

जवाबों:


218

त्रुटि संदेश अपर्याप्त रूप से जानकारीपूर्ण है, और यह मेरी गलती है। उसके लिए माफ़ करना।

आप जिस समस्या का सामना कर रहे हैं वह इस तथ्य का परिणाम है कि सहसंयोजक केवल संदर्भ प्रकारों पर काम करता है।

आप शायद कह रहे हैं "लेकिन IAअभी एक संदर्भ प्रकार है"। हाँ यही है। लेकिन आप यह नहीं कहा है कि T के बराबर है IA । आपने कहा कि Tएक प्रकार है जो लागू होता है IA , और एक मूल्य प्रकार एक इंटरफ़ेस को लागू कर सकता है । इसलिए हम नहीं जानते कि सहसंयोजक काम करेगा या नहीं, और हम इसे अस्वीकार कर देते हैं।

यदि आप कोविरियस काम करना चाहते हैं तो आपको संकलक को बताना होगा कि प्रकार पैरामीटर classबाधा के साथ-साथ IAइंटरफ़ेस बाधा के रूप में एक संदर्भ प्रकार है ।

त्रुटि संदेश वास्तव में कहना चाहिए कि रूपांतरण संभव नहीं है क्योंकि सहसंयोजक को संदर्भ-प्रकार-नेस की गारंटी की आवश्यकता होती है, क्योंकि यह मूलभूत समस्या है।


3
आपने कहा कि यह आपकी गलती क्यों है?
1549 में user4951

77
@ user4951: क्योंकि मैंने सभी त्रुटि संदेशों सहित रूपांतरण जाँच तर्क को लागू किया।
एरिक लिपपर्ट

@BurnsBA यह केवल एक "दोष" है, जो कार्य-बोध में है - तकनीकी रूप से कार्यान्वयन के साथ-साथ त्रुटि संदेश भी पूरी तरह से सही है। (यह सिर्फ इतना है कि अनिश्चितता का त्रुटि विवरण वास्तविक कारणों पर विस्तृत हो सकता है। लेकिन कुछ वर्षों पहले सी ++ टेम्पलेट त्रुटि संदेशों की तुलना में जेनेरिक के साथ अच्छी त्रुटियों का उत्पादन करना कठिन है।)
पीटर - रिंइक मोनिका

3
@ पीटरए.साइडर: मैं इसकी सराहना करता हूं। लेकिन रोसलिन में त्रुटि रिपोर्टिंग तर्क को डिजाइन करने के लिए मेरा प्राथमिक लक्ष्य विशेष रूप से "मूल कारण" की पहचान करने के लिए न केवल क्या नियम का उल्लंघन किया गया था, जहां संभव हो, पर कब्जा करने के लिए विशेष रूप से था। उदाहरण के लिए, त्रुटि संदेश क्या होना चाहिए customers.Select(c=>c.FristName)? C # विनिर्देश बहुत स्पष्ट है कि यह एक अधिभार रिज़ॉल्यूशन त्रुटि है: सेलेक्ट नाम के लागू तरीकों का सेट जो लेम्बडा को खाली कर सकता है। लेकिन मूल कारण यह है कि FirstNameएक टाइपो है।
एरिक लिपर्ट

3
@ पीटरए. श्नाइडर: मैंने यह सुनिश्चित करने के लिए बहुत काम किया कि जेनेरिक प्रकार की खोज और लैम्ब्डा से जुड़े परिदृश्यों ने डेवलपर को किस त्रुटि संदेश को निकालने में मदद करने के लिए उपयुक्त उत्तराधिकारियों का उपयोग किया। लेकिन मैंने रूपांतरण त्रुटि संदेशों पर बहुत कम अच्छा काम किया, खासकर जहाँ विचरण का संबंध था। मुझे हमेशा इस बात का पछतावा होता है।
एरिक लिपर्ट

26

मैं सिर्फ एरिक के उत्कृष्ट अंदरूनी उत्तर को उन लोगों के लिए एक कोड उदाहरण के साथ पूरक करना चाहता था जो सामान्य बाधाओं से परिचित नहीं हो सकते हैं।

Somethingइस तरह से हस्ताक्षर बदलें : classबाधा पहले आना होगा

public static IList<T> Something<T>(IEnumerable<T> foo) where T : class, IA

2
मैं उत्सुक हूँ ... वास्तव में आदेश के महत्व के पीछे क्या कारण है?
टॉम राइट ने

5
@TomWright - कल्पना निश्चित रूप से, कई "क्यों?" का उत्तर शामिल नहीं करता है। प्रश्न, लेकिन इस मामले में यह स्पष्ट करता है कि तीन अलग-अलग प्रकार की बाधाएँ हैं, और जब तीनों का उपयोग किया जाता है, तो उन्हें विशेष रूप से होना चाहिएprimary_constraint ',' secondary_constraints ',' constructor_constraint
डेमियन_इन_उन्नीवर

2
@ सही: डेमियन सही है; वहाँ कोई विशेष कारण नहीं है कि मैं पार्सर के लेखक की सुविधा के अलावा अन्य के बारे में पता कर रहा हूँ। यदि मेरे पास मेरे शराबी थे, तो प्रकार की बाधाओं के लिए वाक्यविन्यास काफी अधिक होगा । classबुरा है क्योंकि इसका अर्थ है "संदर्भ प्रकार", "वर्ग" नहीं। मैं कुछ क्रिया के साथ खुश होता, जैसेwhere T is not struct
एरिक लिपर्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.