2010-10-12 16 views
31

से अनुमानित नहीं किया जा सकता है शायद मैं अधिक काम कर रहा हूं, लेकिन यह संकलित नहीं है (CS0411)। क्यूं कर?विधि के लिए प्रकार तर्कों का उपयोग

interface ISignatur<T> 
{ 
    Type Type { get; } 
} 

interface IAccess<S, T> where S : ISignatur<T> 
{ 
    S Signature { get; }  
    T Value { get; set; } 
} 

class Signatur : ISignatur<bool> 
{ 
    public Type Type 
    { 
     get { return typeof(bool); } 
    } 
} 

class ServiceGate 
{ 
    public IAccess<S, T> Get<S, T>(S sig) where S : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 
} 

static class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     var access = service.Get(new Signatur()); // CS4011 error 
    } 
} 

कोई भी विचार क्यों नहीं? या कैसे हल करें?

+1

शायद त्रुटि आप प्राप्त जोड़ने ... – vulkanino

+1

एरिक Lippert के जवाब की तरह कुछ है करने के लिए है यहां, उनके ब्लॉग पोस्ट के साथ वह लिंक करता है, क्यों एक बहुत अच्छा स्पष्टीकरण है। असल में, अगर मैं सही ढंग से याद करता हूं, तो संकलक जेनेरिक बाधाओं का उपयोग करके प्रकारों का अनुमान नहीं लगाएगा।http://stackoverflow.com/questions/3630153/generic-extension-method-type-argument-cannot-be-inferred-from-the-usage/3630202#3630202 –

उत्तर

42

Get<S, T> दो प्रकार के तर्क लेता है। जब आप service.Get(new Signatur()); पर कॉल करते हैं तो संकलक कैसे जानता है कि T क्या है? आपको इसे अपने प्रकार के पदानुक्रमों के बारे में स्पष्ट रूप से पास करना होगा या कुछ और बदलना होगा। इसे स्पष्ट रूप से पास करना इस तरह दिखेगा:

service.Get<Signatur, bool>(new Signatur()); 
+0

हां, मैं स्पष्टीकरण कॉल से बचना चाहता था। लेकिन अगर एरिक लिपर्ट की व्याख्या के अनुसार, जेनेरिक बाधाओं को सामान्य रिटर्न प्रकारों को हल करने के लिए उपयोग नहीं किया जाता है, तो यह काम नहीं करेगा। धन्यवाद! – Ben

8

Kirk's answer सही है। एक नियम के रूप में, आपके टाइप हस्ताक्षर के साथ कोई भाग्य नहीं होगा जब आपके विधि हस्ताक्षर में पैरामीटर के जेनेरिक प्रकार पैरामीटर हैं।

class ServiceGate<T> 
{ 
    public IAccess<S, T> Get<S>(S sig) where S : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 
} 

तो कोड आप CS0411 के साथ पोस्ट:

अपने विशेष मामले में, यह आप संभवतः वर्ग स्तर तक T प्रकार पैरामीटर के लिए कदम सकता है और फिर अपने Get पद्धति पर प्रकार निष्कर्ष मिल रहा है त्रुटि फिर से लिखा जा सकता है के रूप में:

static void Main() 
{ 
    // Notice: a bit more cumbersome to write here... 
    ServiceGate<SomeType> service = new ServiceGate<SomeType>(); 

    // ...but at least you get type inference here. 
    IAccess<Signatur, SomeType> access = service.Get(new Signatur()); 
} 
0

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

नीचे एक वैकल्पिक कार्यान्वयन है जो संकलित करेगा। मैंने IAccess इंटरफ़ेस को केवल T सामान्य प्रकार पैरामीटर के लिए संशोधित किया है।

interface ISignatur<T> 
{ 
    Type Type { get; } 
} 

interface IAccess<T> 
{ 
    ISignatur<T> Signature { get; } 
    T Value { get; set; } 
} 

class Signatur : ISignatur<bool> 
{ 
    public Type Type 
    { 
     get { return typeof(bool); } 
    } 
} 

class ServiceGate 
{ 
    public IAccess<T> Get<T>(ISignatur<T> sig) 
    { 
     throw new NotImplementedException(); 
    } 
} 

static class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     var access = service.Get(new Signatur()); 
    } 
} 
2

अब मेरा उद्देश्य एक जोड़ी को मूल प्रकार और एक प्रकार की परिभाषा (आवश्यकता ए) के साथ रखना था। प्रकार की परिभाषा के लिए मैं विरासत (आवश्यकता बी) का उपयोग करना चाहता हूं। मूल प्रकार (आवश्यकता सी) पर स्पष्ट ज्ञान के बिना उपयोग संभव होना चाहिए।

ठीक आइए introducte Get2:

class ServiceGate 
{ 
    public IAccess<C, T> Get1<C, T>(C control) where C : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 

    public IAccess<ISignatur<T>, T> Get2<T>(ISignatur<T> control) 
    { 
     throw new NotImplementedException(); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     //var bla1 = service.Get1(new Signatur()); // CS0411 
     var bla = service.Get2(new Signatur()); // Works 
    } 
} 

ठीक है, लेकिन इस समाधान पहुँच

बाद मैं अब जानते हैं कि gernic की कमी सामान्य वापसी प्रकार को सुलझाने के लिए इस्तेमाल नहीं कर रहे हैं, मैं एक छोटा सा प्रयोग requriement नहीं बी

अगला कोशिश:

class ServiceGate 
{ 
    public IAccess<C, T> Get3<C, T>(C control, ISignatur<T> iControl) where C : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 

} 

class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     //var bla1 = service.Get1(new Signatur()); // CS0411 
     var bla = service.Get2(new Signatur()); // Works 
     var c = new Signatur(); 
     var bla3 = service.Get3(c, c); // Works!! 
    } 
} 

अच्छा! अब संकलक जेनेरिक रिटर्न प्रकारों का अनुमान लगा सकता है। लेकिन मुझे यह पसंद नहीं है। अन्य कोशिश:

class IC<A, B> 
{ 
    public IC(A a, B b) 
    { 
     Value1 = a; 
     Value2 = b; 
    } 

    public A Value1 { get; set; } 

    public B Value2 { get; set; } 
} 

class Signatur : ISignatur<bool> 
{ 
    public string Test { get; set; } 

    public IC<Signatur, ISignatur<bool>> Get() 
    { 
     return new IC<Signatur, ISignatur<bool>>(this, this); 
    } 
} 

class ServiceGate 
{ 
    public IAccess<C, T> Get4<C, T>(IC<C, ISignatur<T>> control) where C : ISignatur<T> 
    { 
     throw new NotImplementedException(); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     ServiceGate service = new ServiceGate(); 
     //var bla1 = service.Get1(new Signatur()); // CS0411 
     var bla = service.Get2(new Signatur()); // Works 
     var c = new Signatur(); 
     var bla3 = service.Get3(c, c); // Works!! 
     var bla4 = service.Get4((new Signatur()).Get()); // Better... 
    } 
} 

मेरे अंतिम समाधान ISignature<B, C>, जहां बी आधार प्रकार और सी परिभाषा ... IST

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