2012-03-08 16 views
5

यह हिस्सा जिज्ञासा और हिस्सा है क्योंकि मैं बस इसका उपयोग करने की कोशिश कर रहा था। यदि आपके पास निम्न परिभाषाएं हैं, तो संकलक द्वारा इसकी अनुमति नहीं है क्योंकि यह कहती है कि सदस्य पहले ही परिभाषित है। जेनेरिक प्रकार पैरामीटर के अनन्य अधिभार की अनुमति न देने के पीछे तर्क क्या है?सामान्य प्रकार पैरामीटर ओवरलोडिंग अस्वीकृत?

void Get<T>() where T: struct {} 
void Get<T>() where T: class {} 

ऐसा लगता है कि इसमें कोई अंतर्निहित समस्या नहीं है। कोई तर्क दे सकता है कि यह हमेशा स्पष्ट नहीं होता है कि संकलक को उन मामलों में चुनना चाहिए जहां परिभाषा ओवरलैप होती है (लेकिन एक सामान्य संकल्प सबसे विशिष्ट मिलान होता है)।

क्या कोई मुझे संसाधन को समझने या इंगित करने में मदद कर सकता है कि यह अस्वीकार करने के पीछे तर्क क्या है?

+0

ब्याज से, आपका वास्तविक उपयोग केस किस प्रकार की कोशिश कर रहा था? – AakashM

+0

@AakashM: सरल, मुझे गैर-शून्य मूल्य प्रकारों की तुलना में एक अलग तरीके से निरर्थक प्रकारों को परिवर्तित करने की आवश्यकता थी। मैंने सोचा कि एक सामान्य अधिभार इसे ठीक करने का एक त्वरित तरीका था। विधि एक ऑब्जेक्ट और एक प्रकार का param लेता है और मैं प्रकार param को प्रतिबंधित नहीं कर सकता (ठीक है, मैं कर सकता हूं, लेकिन मैं इसे अधिभारित नहीं कर सकता)। – Abel

उत्तर

9

एरिक Lippert पहले से ही इस एक जवाब सामान्य कमी और विधि हस्ताक्षर पर एक ब्लॉग पोस्ट में,: CLR में विधि हस्ताक्षर का हिस्सा नहीं हैं सामान्य प्रकार पर http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

प्रतिबन्ध है, इसलिए यदि आप दो विधियों नहीं हो सकता है कि सामान्य प्रकार की बाधाओं में केवल भिन्न होता है। सीएलआर समर्थन के बिना सी # को एक समझदार फैशन में समर्थन देने के लिए काफी मुश्किल होगा जो अन्य .NET भाषाओं के अनुकूल है।

+0

यदि आप इसे इस तरह बताते हैं, तो यह तार्किक लगता है। कोई केवल आश्चर्य कर सकता है, _why_ क्या यह विधि हस्ताक्षर का हिस्सा नहीं है? क्या एंडर्स हेजल्सबर्ग के पास इसे किसी अन्य तरीके से डिजाइन करने का कोई अच्छा कारण नहीं था? अभी तक लिपर्ट के लेख को पूरी तरह से पढ़ा नहीं है। सूचक के लिए धन्यवाद। – Abel

+1

मेरा अनुमान है कि यह एक सीएलआर सीमा है - सीएलआर भी एक विधि हस्ताक्षर के सामान्य प्रकार की बाधाओं पर विचार नहीं करता है। विधि हस्ताक्षर के बाइनरी प्रतिनिधित्व में सामान्य बाधाओं का प्रतिनिधित्व करने का कोई तरीका नहीं है, इसलिए यह काफी गहरी सीमा है। – thecoop

+4

@Abel: thecoop सही है; यह सीएलआर की एक सीमा है। हम सिद्धांत रूप में बाधाओं को हस्ताक्षर का एक हिस्सा बना सकते हैं, जो निश्चित रूप से आपके विशिष्ट मामले में सहायक होगा। लेकिन सामान्य मामले में, यह बहुत सारी समस्याएं प्रस्तुत करता है।उदाहरण के लिए: 'शून्य एम () जहां टी: आईएफयू {}' और 'शून्य एम () जहां टी: आईबीआर {}' अलग-अलग विधि हस्ताक्षर होंगे; तो 'एम ' क्या विधि है 'ब्लाह' एक वर्ग है जो 'IFoo' और 'IBar' दोनों लागू करता है? संदिग्ध हस्ताक्षर से निपटने के नियम पहले से ही जटिल हैं; आइए संदिग्ध होने के तरीकों का एक नया नया तरीका न जोड़ें। –

1

Nullable<T> पर बाधा आईएमएचओ वास्तव में दुर्भाग्यपूर्ण है। Nullable<String> या Nullable<Nullable<Nullable<int>>> की तरह कुछ अपमानजनक हो सकता है, लेकिन क्या? पूर्व को अपनी सामग्री के रूप में बॉक्स करें; इसे सामग्री के रूप में अनबॉक्स करें और HasValue सेट करें यदि सामग्री गैर-शून्य है। int के रूप में पूर्व को बॉक्स करें यदि सभी nullables HasValue रिपोर्ट करते हैं, और जब अनबॉक्सिंग करते हैं, तो सभी नेस्टेड आइटमों के HasValue सेट करें यदि सामग्री गैर-शून्य थी।

अन्यथा, मैं सुझाव दूंगा कि आप टाइप पैरामीटर T के साथ एक स्थैतिक जेनेरिक क्लास बनाएं जिसमें एक प्रतिनिधि संपत्ति है जो T पैरामीटर के रूप में स्वीकार करती है। संपत्ति को एक निजी क्षेत्र की सामग्री वापस करनी चाहिए जिसे एक विधि को इंगित करने के लिए प्रारंभ किया जाना चाहिए जो T के प्रकार की जांच करेगा और प्रतिनिधि को struct या class संस्करण पर उचित रूप से सेट करेगा।

यहां मैं जो बात कर रहा हूं उसका एक नमूना है; यह संरचना/वर्ग की बाधाओं के बजाए विभिन्न इंटरफ़ेस बाधाओं का उपयोग करता है, लेकिन समान सिद्धांतों का प्रभावी ढंग से उपयोग किया जा सकता है।

 
     static class _FooDispatcher<T> 
     { 
      public static Action<T> Foo = setupFoo; 

      static void doFooWithIGoodFoo<TT>(TT param) where TT : IGoodFoo 
      { 
       Console.WriteLine("Dispatching as IGoodFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
       param.Foo(); 
      } 
      static void doFooWithIOkayFoo<TT>(TT param) where TT : IOkayFoo 
      { 
       Console.WriteLine("Dispatching as IOkayFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
       param.Foo(); 
      } 
      static void doFooSomehow<TT>(TT param) 
      { 
       Console.WriteLine("Nothing exciting with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
      } 
      static void setupFoo(T param) 
      { 
       System.Reflection.MethodInfo mi; 
       if (typeof(IGoodFoo).IsAssignableFrom(typeof(T))) 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIGoodFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       else if (typeof(IOkayFoo).IsAssignableFrom(typeof(T))) 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIOkayFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       else 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooSomehow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       Foo = (Action<T>)(@Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(typeof(T)))); 
       Foo(param); 
      } 
     } 
संबंधित मुद्दे