2012-06-10 24 views
6

मैं के साथ सी # अभी शुरुआत कर रहा हूँ और इस के लिए किसी भी सवाल का जवाब नहीं मिल सकता है:सही कार्रवाई <Interface> का प्रतिनिधि कैसे करें?

इम कुछ इंटरफ़ेस पैरामीटर के साथ क्रिया को सौंपने की कोशिश कर रहा है, लेकिन वस्तुओं है कि इस इंटरफ़ेस का विस्तार (या वर्ग)

साथ कार्यों के माध्यम से धक्का
// some class extending interface 
public class IntEvent : IFace{} 
public class MoveEvent : IFace{} 

// function i like to use to verify Action 
static void setAction(Action<IFace> evt) { 
    // evt ... 
} 
// function to delegate as Action 
static void evtCheck(IntEvent evt) { 
    // some func 
} 
static void evtMove(MoveEvent evt) { 
    // some func 
} 
// class { 
// call method inside class and delegate this function : 
setAction(evtCheck); 
setAction(evtMove); 

मुझे एक त्रुटि मिल रही है कि "evtCheck(IntEvent) को Action<IFace> में परिवर्तित नहीं किया जा सकता", भले ही IntEventIFace इंटरफ़ेस बढ़ाता है।

मुझे इसे कैसे हल करना चाहिए? शायद मुझे Func या Delegate का उपयोग करना होगा?

उत्तर

7

आप कार्य करना चाहते हैं क्या नहीं कर सकते हैं - आप उम्मीद कर रहे हैं सहप्रसरण, लेकिन Action<T> अपने ही प्रकार पैरामीटर पर contravariant है।

क्योंकि evtCheck अधिक सामान्य IFace प्रकार है कि एक Action<IFace> उदाहरण की उम्मीद की तुलना में अपने तर्क के रूप में एक अधिक विशिष्ट प्रकार (IntEvent) की जरूरत है आप Action<IFace> करने के लिए evtCheck से एक विधि-समूह रूपांतरण नहीं कर सकते। यदि इस तरह के रूपांतरण की अनुमति है, तो आप क्या उम्मीद करेंगे यदि प्रतिनिधि को IFace लागू करने वाले तर्क के साथ निष्पादित किया गया था लेकिन IntEvent नहीं है?

मुझे लगता है कि आप क्योंकि ऐसा लगता है कि वहाँ एक दोष है जैसे आपकी डिजाइन पर फिर से विचार करना चाहिए था, लेकिन अगर आप चाहते हैं, आप इच्छित प्रकार के तर्क का एक डाली बल और एक की संभावना को स्वीकार करने के लिए एक लैम्ब्डा बना सकते हैं InvalidCastException:

setAction(iFace => evtCheck((IntEvent)iface)); 

अधिक संभावना है, आप evtCheck बनाने के लिए एक अधिक विशिष्ट प्रतिनिधि स्वीकार करने के लिए एक अधिक सामान्य प्रकार या setAction स्वीकार कर सकते हैं।

4

Action<T> टी में contravariant है, इसलिए तरीकों लेने एक Action<T> भी Action<U> स्वीकार करेंगे जहां टी यू

से ली गई है

आपका IntEvent वर्ग, तथापि, को लागू करता है IFace इंटरफेस, जिसका अर्थ है कि संकलक अपने setAction() स्वीकार किए जाते हैं कॉल करें, evtCheck() को एक तर्क के साथ कॉल करना संभव होगा जो IFace -डिवेटिव है और IntEvent, रनटाइम त्रुटि और प्रकार की सुरक्षा का स्पष्ट उल्लंघन नहीं है।

अनिवार्य एरिक Lippert संदर्भ: Covariance and contravariance

संपादित करें: मुझे लगता है आपके वर्णन से है कि क्या आप वास्तव में चाहते हैं, विधि पैरामीटर के प्रकार के आधार पर भेदभाव है, इसलिए जैसे आप IntEvent के लिए एक अलग कार्रवाई चाहते हैं, एक अन्य (एक काल्पनिक) DoubleEvent आदि के लिए। यदि ऐसा है, तो आप वास्तव में डबल वर्चुअल प्रेषण के बाद हैं, जो सी # में सीधे समर्थित नहीं है, लेकिन आप इसे Visitor डिज़ाइन पैटर्न का उपयोग करके अनुकरण कर सकते हैं ।

+0

हाँ, यह वही है जो मैं करने की कोशिश कर रहा हूं। क्रिया फ़ंक्शन हमेशा ऑब्जेक्ट की अपेक्षा करते हैं जो समान इंटरफ़ेस या ऑब्जेक्ट का विस्तार करता है ठीक है, मैं आगंतुक डिजाइन पैटर्न देखेंगे। – turbosqel