2012-06-29 16 views
9

मुझे लगता है जवाब नहीं है, लेकिन मैं जानना चाहता हूँ अगर यह कुछ इस तरह करने के लिए संभव है:क्या सी # जेनेरिक विधि प्रकार पैरामीटर को "क्लास 'टाइप पैरामीटर के" असाइन करने योग्य "के रूप में बाध्य करना संभव है?

public class MyGenericClass<TSomeClass> { 
    public void MyGenericMethod<TSomeInterface>() 
     // This doesn't compile. 
     where TSomeClass : TSomeInterface 
    { 
     //... 
    } 
} 

क्या मैं ऊपर (गैर काम कर रहे) उदाहरण में इंगित करने के लिए इसका मतलब यह TSomeInterface ऐसे विवश करने के लिए है कि यह MyGenericClass का अंतर्निहित रूपांतरण हो सकता है कि यह किसी भी बेस क्लास, कार्यान्वित इंटरफेस, या (यदि आप वास्तव में फैंसी प्राप्त करना चाहते हैं) हो सकता है।

नोट: मुझे लगता है कारण है कि इस सी # में लागू नहीं किया गया है कि है कि जेनेरिक की कमी नहीं हैं वास्तव में कोड अनुबंध, जो कि कैसे मैं उन्हें यहाँ का उपयोग करने के कोशिश कर रहा हूँ होना। मुझे वास्तव में परवाह नहीं है कि TSomeInterface किस प्रकार है, जब तक इसे TSomeClass द्वारा कार्यान्वित किया जाता है।

अब तक, मैं इस एक साथ हैक कर लिया है:

public class MyGenericClass<TSomeClass> { 
    public void MyGenericMethod<TIntermediateType, TSomeInterface>() 
     where TIntermediateType : TSomeClass, TSomeInterface 
    { 
     //... 
    } 
} 

यह कम या ज्यादा बाधा है कि मैं चाहता हूँ (कि TSomeClass से, या एक अंतरफलक के मामले में, TSomeInterface में, लागू वारिस चाहिए) को लागू करता है, लेकिन यह बुला बहुत अनाड़ी है, क्योंकि मैं TIntermediateType निर्दिष्ट करने के लिए (भले ही मैं वास्तव में यह TSomeClass के खिलाफ मूल्यांकन करना चाहते हैं) है:

var myGenericInstance = new MyGenericClass<TSomeClass>(); 
myGenericInstance.MyGenericMethod(TSomeClass, TSomeInterface); 

साथ ही, इसके बाद के संस्करण हैक क्योंकि एक फोन करने वाले में कर सकता है टूट गया है ऑरी TSomeClass का उप-वर्ग निर्दिष्ट प्रकार पैरामीटर के रूप में निर्दिष्ट करें, जहां केवल उप-वर्ग TSomeInterface लागू करता है।

कारण यह है कि मैं इस क्या करना चाहते हैं कि मैं एक WCF सेवा के लिए एक धाराप्रवाह कारखाने पैटर्न लिख रहा हूँ है, और मैं साथ कि समाप्ति बिंदु बनाने का प्रयास कर से (संकलन समय पर) फोन करने वाले को रोकने के लिए की तरह होगा एक अनुबंध जो सेवा वर्ग लागू नहीं करता है। मैं इसे रनटाइम पर देख सकता हूं (वास्तव में डब्ल्यूसीएफ वास्तव में मेरे लिए यह करता है), लेकिन मैं संकलन-समय की जांच का एक बड़ा प्रशंसक हूं।

क्या मैं यहां प्राप्त करने के लिए एक बेहतर/अधिक सुरुचिपूर्ण तरीका है?

पर विचार के लिए इस कार्यक्रम को संकलित करता है:

class Program { 
    class Class1 { } 
    class Class2 { } 
    public class MyGenericClass<TSomeClass> { 
     public void MyGenericMethod<TSomeInterface>() where TSomeClass : TSomeInterface { 
     } 
    } 
    static void Main(string[] args) { 
     var inst = new MyGenericClass<Class1>(); 
    } 
} 

सब कुछ अच्छा है

+1

यह व्यावहारिक रूप से असंभव है क्योंकि आप जेनिक्स को रनटाइम के साथ मिश्रित करने की कोशिश कर रहे हैं। – Polity

+0

नहीं, मैं नहीं हूं। मैं बस एक सामान्य बाधा लागू करने की कोशिश कर रहा हूं (जहां तक ​​मैं कह सकता हूं) सी # भाषा अनुमति नहीं देता है (एक प्रकार पैरामीटर को बाधित करता है जैसे कि यह एक श्रेणी के पैरामीटर में एक प्रकार के पैरामीटर का सुपरक्लास या कार्यान्वित इंटरफ़ेस है)। –

+0

जहां तक ​​मैं इसे देखता हूं, आप क्लास जेनेरिक को उस विधि के आधार पर बाध्य करने का प्रयास करते हैं जिसे आप किसी विधि को खिलाते हैं।यदि आप अपनी कक्षा जेनेरिक को बाधित करना चाहते हैं तो आपको कक्षा स्तर (तर्कसंगत) पर ऐसा करने की आवश्यकता है अन्यथा जेआईटी कंपाइलर को ठोस वर्ग बनाने का कोई तरीका नहीं है। – Polity

उत्तर

3

तरह से मैं कारण है कि इस संकलन नहीं है चारों ओर मेरे सिर लपेटो करने में सक्षम था निम्नलिखित है। कंपाइलर खुश है। अब विचार करें मैं Main पद्धति को बदलने:

static void Main(string[] args) { 
    var inst = new MyGenericClass<Class1>(); 
    inst.MyGenericMethod<Class2>(); 
} 

संकलक शिकायत है कि Class1Class2 को लागू नहीं करता है। लेकिन कौन सी लाइन गलत है? बाधा MyGenericMethod पर कॉल पर है, लेकिन कोड की अपमानजनक रेखा MyGenericClass का निर्माण है।

दूसरे शब्दों में, जो एक लाल टेढ़ी-मेढ़ी रेखा हो जाता है?

+1

इन मेरी आदर्श दुनिया यह निश्चित रूप से विधि कॉल होगी, जैसा कि आपने ऐसा करने का प्रयास किया होगा: 'var x = new list (); एस। जोड़ें (5);'। कंपाइलर मानता है कि घोषणा सही है और विधि कॉल अमान्य तर्क का उपयोग कर रहा है। हालांकि वाक्यविन्यास के बारे में सोचने के लिए +1। –

3

जैसा कि this linked question में चर्चा की गई है, आप where खंड के बाईं तरफ वर्तमान घोषणा से नहीं, एक प्रकार पैरामीटर का उपयोग नहीं कर सकते हैं।

तो जैसा कि कि अन्य प्रश्न में w0lf ने सुझाव दिया, आप क्या कर सकते दोनों प्रकार घोषणा (बल्कि विधि की तुलना में) अपने इंटरफेस में प्रदान करना है:

public class MyGenericClass<TSomeClass, TSomeInterface> { 
    where TSomeClass : TSomeInterface 
    public void MyGenericMethod() // not so generic anymore :( 
    { 
     //... 
    } 
} 

कि, हालांकि, बहुत अपनी MyGenericMethod को सीमित करता है और अपने बलों क्लास को हाथ से घोषित करने के लिए आपको किस आधार इंटरफ़ेस की अनुमति है।

तो एक और विकल्प अधिक प्रकार पैरामीटर के साथ एक स्थिर विधि का उपयोग करने के लिए है:

public class MyGenericClass<TSomeClass> { 
    public static void MyGenericMethod<TSomeClass, TSomeInterface> 
             (MyGenericClass<TSomeClass> that) 
     where TSomeClass : TSomeInterface 
    { 
     // use "that" instead of this 
    } 
} 

संभवत: आप इसे यह एक वास्तविक विधि की तरह उपयोगकर्ता के लिए प्रदर्शित करने के लिए एक विस्तार विधि बना सकता है।

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

के कारण के कारण क्यों नहीं?, मेरा अनुमान है कि यह पर्याप्त मूल्य जोड़ने के बिना संकलक को जटिल करेगा। यहां एक discussion by Angelika Langer of the same subject but about Java है। हालांकि सी # और जावा के बीच महत्वपूर्ण अंतर हैं, मुझे लगता है कि उसके निष्कर्ष यहाँ भी लागू हो सकता है:

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

वह एक अच्छा उपयोग केस भी देती है, ऊपर दिए गए लिंक को देखें।

1

एक विस्तार विधि सबसे अच्छा समाधान प्रदान करता है, हालांकि यह आपकी सभी चिंताओं को पूरी तरह से हल नहीं करता है।

public class MyGenericClass<TSomeClass> 
{ 
} 

public static class MyGenericClassExtensions 
{ 
    public static void MyGenericMethod<TSomeClass, TSomeInterface>(this MyGenericClass<TSomeClass> self) 
     where TSomeClass : TSomeInterface 
    { 
     //... 
    } 
} 

यह अभी भी जब MyGenericMethod बुला दोनों प्रकार निर्दिष्ट करने की आवश्यकता है, लेकिन यह TSomeClass के लिए एक गलत प्रकार को निर्दिष्ट से फोन करने वाले के रूप में होने से बचाता है दृष्टिकोण आप के साथ आया था साथ संभव है। इस दृष्टिकोण के साथ, विधि इतनी तरह कहा जा सकता है:

var myGenericInstance = new MyGenericClass<TSomeClass>(); 
myGenericInstance.MyGenericMethod<TSomeClass, TSomeInterface>(); 

यह एक संकलन त्रुटि यदि प्रकार पैरामीटर MyGenericClass साथ MyGenericMethod करने के लिए पहले प्रकार पैरामीटर से मेल नहीं खाता घोषित किया जाता है हो जाएगा।

चूंकि पहले प्रकार पैरामीटर को this तर्क से अनुमानित किया जा सकता है, इसलिए संकलक के लिए उनके अतिरिक्त पैरामीटर यदि दोनों प्रकार के पैरामीटर का अनुमान लगाने के लिए अक्सर संभव होता है।

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

  • कोई संबंधित समस्या नहीं^_^