2010-09-09 7 views
7

मैं इस परिदृश्य है:जेनेरिक अधिभार संकल्प

class Foo { } 

class Foo<T> : Foo { } 

और फिर दो तरीकों

void DoStuff(Foo foo) 
{ 
    DoStuffImpl(foo); 
} 

void DoStuffImpl(Foo foo) 
{ 
    Console.WriteLine("A"); 
}  
void DoStuffImpl<T>(Foo<T> foo) 
{ 
    Console.WriteLine("B"); 
} 

void Main() 
{ 
    DoStuff(new Foo<int>()); // prints A 
} 

(ध्यान दें, कोड ब्राउज़र में लिखा गया था, लेकिन स्थिति मैं का सामना करना पड़ रहा है वर्णन करता है)

मैं सामान्य विधि को कॉल करने के लिए कैसे प्राप्त कर सकता हूं, और बी प्रिंट कर सकता हूं?

क्या यह बिना किसी प्रतिबिंब के किया जा सकता है? मेरे पास कुछ विचार हैं कि इसे प्रतिबिंब के साथ कैसे किया जा सकता है, लेकिन अगर कोई मौजूद है तो मैं क्लीनर समाधान की तलाश में हूं।

नोट: मैं DoStuff जेनेरिक नहीं बना सकता क्योंकि इसका उपयोग डब्ल्यूसीएफ के साथ किया जाएगा और जेनेरिक प्रकारों को खोलने की अनुमति नहीं है।

+3

विधि संकल्प संकलन समय पर होता है, रनटाइम नहीं। एक बार जब आप DoStuff के शरीर में आते हैं, तो कंपाइलर को यह जानने का कोई तरीका नहीं है कि यह मूल रूप से एक Foo था। –

+0

DoStuffImpl के दूसरे अधिभार में टी घोषित किया गया है? –

+0

@Eric, यह DoStuffImpl (Foo foo) होना चाहिए, मेरा बुरा। – andreialecu

उत्तर

17

(मुझे लगता है आप पहले से ही समझ में क्यों यह हो रहा है। यदि नहीं, तो मेरी overload resolution article पढ़ सकते हैं और मुझे पता है अगर यह अभी स्पष्ट नहीं है करते हैं।)

आप सी # 4 उपयोग कर रहे हैं आप सका उपयोग गतिशील टाइपिंग :

void DoStuff(Foo foo) 
{ 
    dynamic d = foo; 
    DoStuffImpl(d); 
} 

नोट कैसे इस करता है सिर्फ एक गतिशील पैरामीटर नहीं - विचार है कि foo सीमित प्रकार Foo या एक उपवर्ग का होना द्वारा, हम करेंगे हमेशा एक वैध 0 है कॉल करने के लिए... यह सिर्फ इतना है कि निष्पादन समय पर सर्वोत्तम विधि निर्धारित की जाएगी, समय संकलित नहीं करें।

आप में पूर्व सी # 4 फंस रहे हैं तो शायद यह डबल प्रेषण के साथ कर सकता:

class Foo 
{ 
    public virtual void CallStuffImpl(FooImplType x) 
    { 
     x.DoStuffImpl(this); 
    } 
} 

class Foo<T> : Foo 
{ 
    public override void CallStuffImpl(FooImplType x) 
    { 
     // Looks like it's redundant, but isn't! "this" is 
     // known to be Foo<T> rather than Foo 
     x.DoStuffImpl(this); 
    } 
} 

तब:

void DoStuff(Foo foo) 
{ 
    foo.CallStuffImpl(this); // Let it dispatch appropriately 
} 
+0

+1, कूल, कोई विचार नहीं था कि ओवरलोड रिज़ॉल्यूशन के लिए डायनामिक का उपयोग किया जा सकता है। –

+0

धन्यवाद जॉन। हाँ, मैं समझता हूं कि यह क्यों हो रहा है। अभी तक सी # 4.0 का उपयोग नहीं कर रहा है, लेकिन अगर यह काम करेगा तो यह स्विच करने का एक अच्छा कारण होगा! – andreialecu

+0

प्री सी # 4.0 वर्कअराउंड के लिए सम्मानित किया गया। वह बहुत चिकना है। – andreialecu

16

अधिभार संकल्प संकलन समय में किया जाता है। जब "DoStuff" संकलित किया जाता है, तो यह पहले ही तय कर चुका है कि DoStuffImpl का कौन सा संस्करण कॉल करना है, और यह तय करता है कि संकलन समय पर उपलब्ध जानकारी के आधार पर, रनटाइम पर उपलब्ध जानकारी नहीं।

वहाँ सी # में विधि भेजने के चार प्रकार के होते हैं:

  • स्थिर भेजने संकलन समय पर स्थिर विधि को चुनता है। रनटाइम पर, चुनी गई विधि को बुलाया जाता है।

  • उदाहरण प्रेषण संकलन समय पर एक उदाहरण विधि चुनता है। रनटाइम पर, चुनी गई विधि को बुलाया जाता है। (यह गैर-वर्चुअल इंस्टेंस विधियों और "बेस" के साथ वर्चुअल विधियों पर प्रेषित प्रेषण का रूप है)

  • आभासी प्रेषण संकलन समय पर एक उदाहरण विधि चुनता है। रनटाइम पर, ऑब्जेक्ट के रनटाइम प्रकार पर उस विधि के अधिकांश ओवरराइडिंग संस्करण को कॉल किया जाता है।

  • गतिशील प्रेषण संकलन समय (*) पर कुछ भी नहीं करता है।रनटाइम पर कंपाइलर फिर से शुरू होता है और रनटाइम पर संकलन-समय विश्लेषण करता है, और नया नया कोड जेनरेट करता है जो कि लिखा गया था, क्या आपने इसे पहले स्थान पर संकलित समय पर सही तरीके से प्राप्त किया था। यह उतना महंगा है जितना लगता है; सौभाग्य से परिणाम कैश किया गया है ताकि दूसरे कॉल पर, आपको फिर से विश्लेषण और कोडेजन की सभी लागत नहीं मिलती है।

गतिशील प्रेषण केवल सी # 4, या वीबी के किसी भी संस्करण में उपलब्ध है।

(*) यह बिल्कुल सही नहीं है; ऐसी कुछ परिस्थितियां हैं जिनमें संकलक समय संकलन पर विश्लेषण कर सकते हैं भले ही विधि के तर्क गतिशील हैं। विवरण जटिल हैं।

+0

धन्यवाद एरिक, ऐसा लगता है कि हमारे लिए सी # 4.0/वीएस -2010 पर जाने का समय है, गतिशील प्रेषण सबसे साफ समाधान की तरह लगता है। – andreialecu

+0

उद्धरण: "संकलक फिर से शुरू होता है"। डीएलआर क्या करता है, यह सिर्फ भाषण का एक आंकड़ा है, है ना? –

+0

@ हंस: यह डीएलआर प्रति से नहीं है; यह एक डीएलआर इंटरफेस को लागू करने वाला सी # बाइंडर है। (विशेष रूप से मुझे विश्वास नहीं है कि यह dlr.codeplex.com पर उपलब्ध है।) –