2011-12-14 19 views
45

मेरे पास जेनेरिक तरीकों के साथ बहुत मज़ाकिया मज़ा (मजेदार इरादा) है। ज्यादातर मामलों में सी # प्रकार अनुमान यह समझने के लिए पर्याप्त स्मार्ट है कि यह सामान्य जेनेरिक तरीकों पर किस सामान्य तर्क का उपयोग करना चाहिए, लेकिन अब मुझे एक ऐसा डिज़ाइन मिला है जहां सी # कंपाइलर सफल नहीं होता है, जबकि मुझे लगता है कि यह खोजने में सफल हो सकता है सही प्रकारसी # मेरे सामान्य प्रकार का अनुमान क्यों नहीं लगाता है?

क्या कोई मुझे बता सकता है कि संकलक इस मामले में थोड़ा गूंगा है, या क्या कोई स्पष्ट कारण है कि यह मेरे सामान्य तर्कों का अनुमान नहीं लगा सकता है?

कोड यह रहा:

वर्ग और इंटरफ़ेस परिभाषाएँ:

interface IQuery<TResult> { } 

interface IQueryProcessor 
{ 
    TResult Process<TQuery, TResult>(TQuery query) 
     where TQuery : IQuery<TResult>; 
} 

class SomeQuery : IQuery<string> 
{ 
} 

कुछ कोड है कि संकलन नहीं करता है:

class Test 
{ 
    void Test(IQueryProcessor p) 
    { 
     var query = new SomeQuery(); 

     // Does not compile :-(
     p.Process(query); 

     // Must explicitly write all arguments 
     p.Process<SomeQuery, string>(query); 
    } 
} 

ऐसा क्यों है? मुझे यहां क्या समझ नहीं आ रहा है?

विधि IQueryProcessor.Process (TQuery) के लिए प्रकार तर्क के उपयोग से नहीं लगाया जा सकता:

यहाँ संकलक त्रुटि संदेश (यह हमारी कल्पना के लिए बहुत कुछ नहीं छोड़ता) है। स्पष्ट रूप से प्रकार तर्कों को निर्दिष्ट करने का प्रयास करें।

कारण मेरा मानना ​​है कि सी # यह अनुमान लगाने के लिए सक्षम होना चाहिए निम्नलिखित की वजह से है:

  1. मैं एक वस्तु है कि IQuery<TResult> लागू करता है की आपूर्ति।
  2. यह केवल IQuery<TResult> संस्करण जो लागू करता है IQuery<string> है और इस प्रकार TResult string होना चाहिए।
  3. इस जानकारी के साथ संकलक ट्रेशल्ट और TQuery है।

    public interface IQueryProcessor 
    { 
        TResult Process<TResult>(IQuery<TResult> query); 
    } 
    
    // Implementation 
    sealed class QueryProcessor : IQueryProcessor { 
        private readonly Container container; 
    
        public QueryProcessor(Container container) { 
         this.container = container; 
        } 
    
        public TResult Process<TResult>(IQuery<TResult> query) { 
         var handlerType = 
          typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult)); 
         dynamic handler = container.GetInstance(handlerType); 
         return handler.Handle((dynamic)query); 
        } 
    } 
    

    IQueryProcessor इंटरफेस अब एक IQuery<TResult> पैरामीटर में लेता है:

समाधान

मेरे लिए सबसे अच्छा समाधान IQueryProcessor इंटरफेस बदल सकते हैं और कार्यान्वयन में गतिशील टाइपिंग उपयोग करने के लिए किया गया था। इस तरह यह TResult वापस कर सकता है और इससे उपभोक्ता के दृष्टिकोण से समस्याएं हल हो जाएंगी। वास्तविक कार्यान्वयन के लिए हमें कार्यान्वयन में प्रतिबिंब का उपयोग करने की आवश्यकता है, क्योंकि कंक्रीट क्वेरी प्रकारों की आवश्यकता है (मेरे मामले में)। लेकिन यहां बचाव के लिए गतिशील टाइपिंग आता है जो हमारे लिए प्रतिबिंब करेगा। आप इस article में इसके बारे में अधिक पढ़ सकते हैं।

+0

त्रुटि संदेश क्या है:

मेरा प्रासंगिक लेख पढ़ने के लिए नहीं बल्कि यह एक है? –

+4

कंपाइलर को पता नहीं है कि 'TResult' का उपयोग करने के लिए क्या है। उस समय इसे निर्णय लेने की आवश्यकता होती है, यह नहीं जानता कि आप इसे 'स्ट्रिंग' में डाल देंगे (इसलिए शायद इसे 'स्ट्रिंग' अनुमानित करना चाहिए)।और यहां तक ​​कि अगर यह पता था, तो यह कानूनी रूप से 'प्रक्रिया ' हो सकता है, जहां 'customClass'' स्ट्रिंग' से प्राप्त कोई भी वर्ग है। यह भी देखें: [रिटर्न टाइप अनुमान सदस्य समूहों पर काम नहीं करता है] (http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference- करता है-नहीं-काम-ऑन-सदस्य-groups.aspx)। –

+0

और @ रेमंड कहते हैं कि वह एक .NET लड़का नहीं है ... pshaw –

उत्तर

36

लोगों का एक समूह ने इंगित किया है कि सी # बाधाओं के आधार पर सम्मेलन नहीं करता है। यह सही है, और सवाल के लिए प्रासंगिक है। तर्क और उनके संबंधित औपचारिक पैरामीटर प्रकार की जांच करके इन्हें किया जाता है और यह अनुमान जानकारी का एकमात्र स्रोत है।

लोगों का एक गुच्छा तो इस लेख से जुड़ा हुआ है:

http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

कि लेख बाहर की तारीख और अप्रासंगिक सवाल करने के लिए दोनों है। यह पुराना है क्योंकि यह सी # 3.0 में किए गए एक डिजाइन निर्णय का वर्णन करता है जिसे हम सी # 4.0 में उलटते हैं, ज्यादातर उस लेख के जवाब के आधार पर। मैंने अभी आलेख में उस प्रभाव के लिए एक अद्यतन जोड़ा है।

यह अप्रासंगिक है क्योंकि लेख लगभग विधि समूह तर्क से सामान्य प्रकार के औपचारिक पैरामीटर पर वापसी प्रकार अनुमान है। यही वह स्थिति नहीं है जिस पर मूल पोस्टर पूछता है।

http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

+2

आपके उत्तर के लिए धन्यवाद (उत्तर)। क्या सी # कंपाइलर भविष्य में बाधा अनुमान लगाने के लिए संभव है, या क्या यह सवाल से बाहर है? – Steven

+0

मैं कहूंगा कि इस तरह की धारणा प्रश्न से बाहर है। एरिक ने एक टिप्पणी में कहा, "यह सी # भाषा के डिजाइन के दीर्घकालिक सिद्धांतों के अनुसार एक जानबूझकर डिजाइन विकल्प है।" – Brian

+0

@ स्टेवन: ब्रायन सही है; हमारे पास तथ्यों की सूची में बाधाओं को जोड़ने का कोई इरादा नहीं है जिसका उपयोग सम्मेलन बनाने के लिए किया जाता है। –

14

सी # जेनेरिक विधि के रिटर्न प्रकार के आधार पर जेनेरिक प्रकारों का अनुमान नहीं लगाएगा, केवल विधि के लिए तर्क।

यह प्रकार के अनुमान के हिस्से के रूप में बाधाओं का भी उपयोग नहीं करता है, जो आपके लिए प्रकार की आपूर्ति से सामान्य बाधा को समाप्त करता है।

विवरण के लिए, Eric Lippert's post on the subject देखें।

7

यह अनुमानित प्रकारों में बाधाओं का उपयोग नहीं करता है।इसके बजाय यह प्रकार (जब संभव हो) infers और फिर बाधाओं की जांच करता है।

इसलिए, जबकि केवल TResult का उपयोग किया जा सकता है जिसका उपयोग SomeQuery पैरामीटर के साथ किया जा सकता है, यह इसे नहीं देख पाएगा।

यह भी ध्यान दें कि के लिए IQuery<int> को लागू करने के लिए यह पूरी तरह से संभव होगा, जो कि संकलक पर सीमा है, यह एक बुरा विचार नहीं हो सकता है।

+0

यह एकमात्र उत्तर है जो तर्कसंगत स्थिति को समझाता है! अभी तक कोई वोट नहीं .. – nawfal

4

कल्पना इस सुंदर स्पष्ट रूप से देता है:

धारा 7.4.2 प्रकार निष्कर्ष

तो तर्क की आपूर्ति की संख्या विधि में पैरामीटर की संख्या की तुलना में अलग है, तो अनुमान तुरंत विफल रहता है । अन्यथा, मान लेते हैं कि सामान्य विधि निम्नलिखित हस्ताक्षर हैं:

Tr एम (टी 1 x 1 ... Tm xm)

(ई 1 ... एम) प्रपत्र एम की एक विधि कॉल प्रकार निष्कर्ष का कार्य करने के लिए है के साथ

अद्वितीय प्रकार के तर्क S1 ... प्रत्येक प्रकार के पैरामीटर X1 के लिए Sn ... एक्सएन ताकि कॉल एम (ई 1 ... एम) मान्य हो जाए।

जैसा कि आप देख सकते हैं, वापसी प्रकार का प्रकार प्रकार अनुमान के लिए उपयोग नहीं किया जाता है। यदि विधि कॉल सीधे टाइप तर्क तर्क में मैप नहीं करता है तो तुरंत विफल हो जाता है।

कंपाइलर यह नहीं मानता कि आप stringTResult तर्क के रूप में चाहते थे, न ही यह कर सकते हैं। स्ट्रिंग से व्युत्पन्न TResult की कल्पना करें। दोनों वैध होंगे, तो कौन सा चयन करना है? स्पष्ट होना बेहतर है।

+0

यह न केवल वापसी प्रकार है जो प्रकार अनुमान को सफल बना देगा। प्रकार 'IQuery ' लागू करता है। – Steven

+3

ध्यान दें कि पहला हाइलाइट किया गया कथन एक त्रुटि है; जब हमने नाम और वैकल्पिक तर्क जोड़े, तो यह लाइन कभी अपडेट नहीं हुई थी, और उनके विस्तारित रूप में लागू "पैरा" विधियों पर टाइप अनुमान के साथ असंगत भी है। विनिर्देश का एक भविष्य संस्करण उन्हें ध्यान में रखने के लिए लाइन को सही करेगा। –

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