2016-02-17 9 views
5

के साथ इंटरफ़ेस का जेनेरिक कार्यान्वयन मेरे पास एक दिलचस्प स्थिति है जहां मैं एक इंटरफ़ेस को लागू करने के लिए एक प्रकार पैरामीटर का उपयोग करने वाली बेस क्लास का उपयोग करना चाहता हूं और चीजों को विरासत कक्षाओं के साथ भी रखना चाहता हूं।निर्दिष्ट प्रकार

public interface ICalculator 
{ 
    void Process(ICalculationModel calculationModel); 
} 

public abstract class CalculatorBase<T> :ICalculator where T : ICalculationModel 
{ 
    // Compiler moans that Process(ICalculationModel calculationModel) isn't implemented 
    public abstract void Process(T calculationModel); 
} 

public class PipeworkInspections : CalculatorBase<GasSafetyModel> 
{ 
    public override void Process(GasSafetyModel documentModel){ 
     //snip 
    } 
} 

क्या मुझे कुछ सामान्य 'कहां' खंड या कुछ के साथ याद आ रही है? मेरे सिर में यह काम करना चाहिए। या क्या कंपाइलर को इंटरफ़ेस परिभाषा के समान ही कार्यान्वयन की आवश्यकता है?

मैं आसानी से टाइप पैरामीटर को आईसील्यूलेटर में नहीं ले जा सकता क्योंकि वहां बहुत से स्थान हैं जिनका उपयोग सामान्य के लिए बिना किसी आवश्यकता के किया जाता है।

यह चीजों को साफ़ कर दिया गया है। जानकारी के लिए धन्यवाद। अब स्पष्ट रूप से एक समाधान इंटरफेस को प्रकार पैरामीटर लेना है। हालांकि आईसील्यूलेटर का उपयोग कई स्थानों पर किया जाता है और संदर्भित किया जाता है जैसे कि ICalculator अब मुझे कंपाइलर त्रुटियां मिलती हैं यदि मैं इंटरफेस में टाइप पैरामीटर को छोड़ देता हूं जो आईसीक्यूल्यूलेटर का संदर्भ देता है ... क्या ऐसा करने के लिए आर्किटेक्ट करने का कोई तरीका है जो काम करना चाहिए !?

+0

मेरा मानना ​​है कि यह समान होना चाहिए कि यह 'आईक्यूल्यूलेटर' में कैसा दिखाई देता है। हालांकि, चूंकि मैं मुख्य रूप से जावा सामान करता हूं और सी # नहीं, मैं निश्चित रूप से यह नहीं कह सकता। – Powerlord

+0

यह काम नहीं कर सकता क्योंकि आप तब 'आईसील्यूलेटर सी = नया पाइपवर्क इंस्पेक्शन() कर सकते हैं; सी। प्रोसेस (नया अन्य मॉडल()) 'जो सुरक्षित नहीं है। सबसे अच्छा आप कर सकते हैं 'ICalculator.Process' को लागू करना और फिर सामान्य कार्यान्वयन के अंदर डालना। – Lee

उत्तर

0

अगर यह काम आप कुछ इस तरह कहने के लिए सक्षम होगा:

PipeworkInspections pipeworks = new PipeworkInspections(); 
ICalculator calculator = pipeworks; 

NuclearPowerSafetyModel nuclearModel = new NuclearPowerSafetyModel(); 
calculator.Process(nuclearModel); // <-- Oops! 

कि शायद नहीं है जिसकी आपको चाहता था ...

8

मेरे सिर में यह काम करना चाहिए।

समस्या तब आपके सिर में है! :-) यह काम नहीं करना चाहिए। चलो देखते हैं क्यों।

interface ICage 
{ 
    void Enclose(Animal animal); 
} 
class ZooCage<T> : ICage where T : Animal 
{ 
    public void Enclose(T t) { ... } 
} 
... 

var giraffePaddock = new ZooCage<Giraffe>(); 
var cage = (ICage)giraffePaddock; 
var tiger = new Tiger(); 
icage.Enclose(tiger); 

और अब वहाँ जिराफ मंडूक में एक बाघ है, और जीवन जिराफ के लिए बाघ के लिए अच्छा है, लेकिन खराब है। यही कारण है कि यह अवैध है।

या क्या संकलक को इंटरफ़ेस परिभाषा के समान ही कार्यान्वयन की आवश्यकता है?

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

interface I 
{ 
    Animal GetAnimal(); 
} 
class C : I 
{ 
    public Giraffe GetAnimal() { ... } // not legal. 
} 

अनुबंध एक जानवर की आवश्यकता है; आप एक जिराफ प्रदान करते हैं। यह काम करना चाहिए, तार्किक रूप से, लेकिन यह सी # में कानूनी नहीं है। (यह सी ++ में है।)

इस साइट पर कई प्रकार के प्रश्नों को देखें, कारणों के कारण रिटर्न प्रकार कॉन्वर्सिस के बारे में।

इसी प्रकार पैरामीटर प्रकार contravariance के लिए

:

interface I 
{ 
    void PutMammal (Mammal mammal); 
} 
class C : I 
{ 
    public PutMammal(Animal animal) { ... } // not legal. 
} 

फिर, यह तार्किक समझदार है, अनुबंध के लिए आवश्यक है कि आप एक स्तनपायी लें, और यह किसी भी जानवर को लेता है। लेकिन फिर, यह कानूनी नहीं है।

सी # में कुछ कॉन्वर्सेंट और contravariant संचालन हैं; इस साइट पर उन विषयों पर कई प्रश्नों को देखें, या ericlippert.com या मेरे पिछले msdn ब्लॉग पर covariance और contravariance articles ब्राउज़ करें।

+0

क्या आप किसी भी भाषा के बारे में जानते हैं जो किसी इंटरफ़ेस (या मनोबल समकक्ष) के कार्यान्वयन को विधि के तर्कों के संबंध में contravariant करने की अनुमति देता है? मैंने रिटर्न टाइप कॉन्वर्सिस के साथ कई लोगों के बारे में सुना है (आपने अभी सी ++ का उल्लेख किया है), लेकिन पैरामीटर contravariance नहीं है। – Servy

+0

@ सर्वी: शायद एफिल? मुझे लगता है कि उस फीचर वाले एफिल के बारे में कुछ सुनना याद है। मैंने कभी एफिल का उपयोग नहीं किया है, इसलिए मैं निश्चित रूप से नहीं कह सकता। सी # निश्चित रूप से एक प्रतिनिधि को एक विधि में परिवर्तित करते समय पैरामीटर contravariance की अनुमति देता है, जो मुझे लगता है कि नैतिक समकक्ष कुछ हद तक है; आप एक प्रतिनिधि को एक इंटरफेस के रूप में सोच सकते हैं जिसे एक ही विधि कहा जाता है जिसे Invoke कहा जाता है। –

+0

@ सर्वी: मैंने इसे देखा। एफिल * असुरक्षित * पैरामीटर * कॉन्वर्स * का समर्थन करता है, यही कारण है कि यह मेरे सिर में फंस गया। शेदर एक एफिल जैसी भाषा है जो पैरामीटर contravariance का समर्थन करता है। –

0

आपका इंटरफेस कहते हैं किसी भी वर्ग लागू इस विधि प्रदान करेगा:

void Process(ICalculationModel calculationModel); 

अब स्पष्ट रूप से PipeworkInspections करता नहीं। इसमें कोई विधि नहीं है Process जो ICalculationModel स्वीकार करता है। आईटी में केवल ICalculationModel के विशिष्ट कार्यान्वयन को स्वीकार करने की विधि है। तो आपका संकलन विफल रहता है।

0

हां, आपको सटीक कार्यान्वयन की आवश्यकता है।

एक विकल्प के रूप में आप interface और Process विधि सामान्य कर सकते हैं कि वह आपके लिए काम करता है:

public interface ICalculator<T> where T : ICalculationModel 
{ 
    void Process(T calculationModel); 
} 

public abstract class CalculatorBase<T> : ICalculator where T : ICalculationModel 
{ 
    public abstract void Process(T calculationModel); 
} 
0

मैं एरिक Lippert की प्रतिक्रिया से सहमत: आप नहीं कर सकते। और उन्होंने एक बहुत अच्छे तरीके से समझाया कि ऐसा क्यों होता है।

तुम सच में ऐसा करना चाहते हैं , तो आप अपने अमूर्त वर्ग के लिए निम्न में जोड़ सकते हैं, और यह संकलन होगा:

void ICalculator.Process(ICalculationModel calcMod) 
{ 
    Process((T)calcMod); 
} 

लेकिन आप को पता है तुम क्या कर रहे जरूरत है, अन्यथा आप हो सकता है रनटाइम पर कुछ InvalidCastException

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