2011-01-07 14 views
8

मैंने निम्नलिखित वर्गों और विधियों को परिभाषित किया है:क्यों सी # जेनेरिक ओवरराइड तरीकों के लिए सही ढंग से बंधे नहीं है?

 using System; 
using System.Linq.Expressions; 
using System.Windows.Forms; 

public class ReturnValue<T, S> {} 

public class Something<T> 
{ 
    // Sorry about the odd formatting. Trying to get it to fit nicely... 
    public ReturnValue<T, C> 
    Do<C, S>(C control, Expression<Func<C, S>> controlProperty) 
    where C : Control 
    { 
     return new ReturnValue<T, C>(); 
    } 

    public ReturnValue<T, ToolStripItem> 
    Do<S>(ToolStripItem control, Expression<Func<ToolStripItem, S>> controlProperty) 
    { 
     return new ReturnValue<T, ToolStripItem>(); 
    } 
} 

यह ठीक संकलित करता है। वू हू! आधे रास्ते वहाँ। फिर, मैं इसे बाद में कोड के साथ उपयोग करने का प्रयास करता हूं:

 var toolStripItem = new ToolStripStatusLabel(); 

var something = new Something<string>(); 
something.Do(toolStripItem, t => t.Text); // Does not compile 

हालांकि, यह निम्न त्रुटि संदेश के साथ मर जाता है

प्रकार ToolStripStatusLabel सामान्य प्रकार में टाइप पैरामीटर C के रूप में उपयोग नहीं किया जा सकता है या विधि Something<T>.Do<C,S>(C, Expression<Func<C,S>>)। Xzx77 से Control तक कोई अंतर्निहित संदर्भ रूपांतरण नहीं है।

मुझे ऐसा लगता है कि सी # कंपाइलर इस मामले में विफल रहा है हालांकि दोनों विधियां संदिग्ध विधि घोषणाओं का एक सेट नहीं बनाती हैं। Control और ToolStripStatusLabelComponent के विरासत पेड़ में भाई बहन के रूप में मौजूद है। मुझे लगता है कि संकलक के पास क्लाइंट कोड में विधि आमंत्रण को सही ढंग से बाध्य करने के लिए पर्याप्त जानकारी होगी।

हालांकि, अगर मैं अपनी खुद की भाई कक्षाओं के साथ एक ही काम करता हूं, तो सबकुछ ठीक से संकलित होता है।

 public class Parent {} 
public class Child1 : Parent {} 
public class Child2 : Parent {} 

public class Something2<T> 
{ 
    public ReturnValue<T, C> 
    Do<C, S>(C control, Expression<Func<C, S>> controlProperty) 
    where C : Child1 
    { 
     return new ReturnValue<T, C>(); 
    } 

    public ReturnValue<T, Child2> 
    Do<S>(Child2 control, Expression<Func<Child2, S>> controlProperty) 
    { 
     return new ReturnValue<T, Child2>(); 
    } 
} 

var child2 = new Child2(); 
var something2 = new Something2<string>(); 
something2.Do(child2, c => c.GetType()); // Compiles just fine 

क्या किसी ने कुछ गलत किया है, तो क्या कोई भी प्रकाश डाल सकता है?

उत्तर

11

समस्या यह है कि पहली विधि उम्मीदवार अधिभार संकल्प के लिए सेट में है, क्योंकि प्रकार बाधा C : Control केवल लागू किया जाता है ओवरलोड रिज़ॉल्यूशन के बाद किया गया है। मुझे विश्वास है कि आप इसे जल्दी से बाहर निकालने की उम्मीद कर रहे हैं - और यह नहीं है।

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

प्रकार बाधा सत्यापन है तो लागू ... और विफल रहता है।

मेरे पास blog post on this matter है जो आपको प्रक्रिया को समझने में मदद कर सकता है, और फिर another blog post जहां मैं नियमों को मूर्खतापूर्ण तरीके से लागू करता हूं।

संपादित करें: आपके दूसरे उदाहरण में, तर्क का प्रकार बिल्कुल पहले पैरामीटर में निर्दिष्ट प्रकार है, इसलिए पहली विधि अधिक विशिष्ट होने के समाप्त नहीं होती है। दूसरी विधि कम प्रकार के पैरामीटर होने के कारण जीतती है (मुझे लगता है; मैंने इसे विस्तार से चेक नहीं किया है) और फिर सत्यापित और पास किया जाता है।

इसे वापस कहें ToolStripItem मामले में, आप वास्तव में अपने पहला नमूना एक साधारण परिवर्तन के साथ संकलन कर सकता है:

// Change this 
var toolStripItem = new ToolStripStatusLabel(); 
// To this... 
ToolStripItem toolStripItem = new ToolStripStatusLabel(); 

ToolStripItem को ToolStripStatusLabel से toolStripItem का संकलन समय प्रकार बदलने से दूर "लाभ" लेता है कि पहली विधि थी, तो यह संकलित करता है।

+0

जॉन, यह एक महान स्पष्टीकरण है। धन्यवाद। – realistschuckle

+0

तो दूसरा उदाहरण संकलित क्यों करता है? –

+0

ब्लूराजा (एक महान नाम के अलावा) सही ढंग से लिखता है, जिसे मैंने स्पष्टीकरण पर विचार करने के बाद सोचा था। कोई अंतर्दृष्टि, जॉन? – realistschuckle

0

मुझे लगता है कि तुम सिर्फ अपने कॉल के साथ अधिक स्पष्ट करने की आवश्यकता है:

var toolStripItem = new ToolStripStatusLabel(); 
var something = new Something<string>(); 
something.Do<string>(toolStripItem, t => t.Text); // might compile 
संबंधित मुद्दे