2012-01-14 25 views
18

हर बार मैं एक आत्म-संदर्भ ("रिफ्लेक्सिव") टाइप पैरामीटर बाधा जोड़कर एक सरल इंटरफ़ेस को और अधिक जटिल बना रहा हूं। उदाहरण के लिए, मैं इस बदल सकता:रिफ्लेक्सिव प्रकार पैरामीटर बाधाएं: एक्स <T> जहां टी: एक्स <T> - कोई आसान विकल्प?

में
interface ICloneable 
{ 
    ICloneable Clone(); 
} 

class Sheep : ICloneable 
{ 
    ICloneable Clone() { … } 
} //^^^^^^^^^^ 

Sheep dolly = new Sheep().Clone() as Sheep; 
           //^^^^^^^^ 

:

interface ICloneable<TImpl> where TImpl : ICloneable<TImpl> 
{ 
    TImpl Clone(); 
} 

class Sheep : ICloneable<Sheep> 
{ 
    Sheep Clone() { … } 
} //^^^^^ 

Sheep dolly = new Sheep().Clone(); 

मुख्य लाभ: एक को लागू करने (जैसे Sheep के रूप में) अब इसके आधार प्रकार के बजाय खुद को दर्शा सकते हैं की आवश्यकता को कम टाइप-कास्टिंग (जैसा कोड की अंतिम पंक्ति द्वारा प्रदर्शित किया गया है)।

हालांकि यह बहुत अच्छा है, मैंने यह भी देखा है कि इन प्रकार की पैरामीटर बाधाएं अंतर्ज्ञानी नहीं हैं और अधिक जटिल परिदृश्यों में समझने में प्रवृत्ति वास्तव में मुश्किल हो गई है। *)

प्रश्न: किसी को भी एक और सी # कोड पैटर्न है कि एक ही प्रभाव को प्राप्त होता है या कुछ इसी तरह का पता है, लेकिन एक आसान करने के लिए समझ फैशन में?


*) इस कोड पैटर्न unintuitive और जैसे को समझने के लिए मुश्किल हो सकता है इन तरीकों से: "। तो T एक X<T> है, तो X<T> वास्तव में एक X<X<…<T>…>> कि"

  • घोषणा X<T> where T : X<T> पुनरावर्ती प्रतीत होता है, और एक आश्चर्य हो सकता है क्यों संकलक doesn't get stuck in an infinite loop, तर्क, (लेकिन कमी स्पष्ट रूप से इस तरह हल नहीं है।)

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

+3

आपको यह जानकर खुशी होगी कि यह नाम रखने के लिए काफी आम है: इसे 'उत्सुकता से आवर्ती टेम्पलेट पैटर्न' (संक्षिप्त के लिए सीआरटीपी) कहा जाता है। – Cameron

+1

... और इसमें बाधाओं से कोई लेना देना नहीं है (मानक सी ++ टेम्पलेट्स में उन्हें बिल्कुल नहीं है)। – Krizz

+0

क्या कोई कारण नहीं है कि यह 'इंटरफ़ेस आईसीएलनेबल {टी क्लोन() नहीं है; } '? –

उत्तर

19

मुख्य लाभ: एक को लागू प्रकार अब, उसके आधार प्रकार के बजाय खुद को देखें प्रकार कास्टिंग

की आवश्यकता को कम कर सकते हैं हालांकि यह प्रकार से की तरह लग सकता है बाधा खुद का जिक्र करती है, यह कार्यान्वयन प्रकार को ऐसा करने के लिए मजबूर करती है, जो वास्तव में ऐसा नहीं करती है। लोग इस पैटर्न का उपयोग फॉर्म के पैटर्न को व्यक्त करने के लिए करते हैं, "इस विधि के ओवरराइड को ओवरराइडिंग क्लास के प्रकार को वापस करना होगा", लेकिन वास्तव में यह टाइप सिस्टम द्वारा व्यक्त या लागू बाध्यता नहीं है।मैं यहाँ एक उदाहरण देता हूँ:

http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx

हालांकि यह बहुत अच्छा है, मैं भी देखा है कि इन प्रकार पैरामीटर की कमी सहज नहीं कर रहे हैं और अधिक जटिल स्थितियों में समझने के लिए वास्तव में मुश्किल हो प्रवृत्ति है

हाँ। मैं इस पैटर्न से बचने की कोशिश करता हूं। इसके बारे में तर्क करना मुश्किल है।

क्या किसी को भी एक अन्य सी # कोड पैटर्न पता है जो समान प्रभाव या कुछ समान प्राप्त करता है, लेकिन एक आसान-समझने वाली फैशन में?

सी # नहीं, नहीं। यदि आप इस तरह की चीज आपको रूचि देते हैं तो आप हास्केल प्रकार प्रणाली को देखने पर विचार कर सकते हैं; हास्केल के "उच्च प्रकार" प्रकार के पैटर्न के प्रकार का प्रतिनिधित्व कर सकते हैं।

घोषणा X<T> where T : X<T> पुनरावर्ती प्रतीत होता है, और एक आश्चर्य हो सकता है क्यों संकलक अनंत लूप, तर्क में अटक न जाए, "अगर T एक X<T> है, तो X<T> वास्तव में एक X<X<…<T>…>> है।"

ऐसे सरल रिश्तों के बारे में तर्क करते समय संकलक कभी अनंत लूप में नहीं आता है। हालांकि, सामान्य प्रकार के सामान्य प्रकार के नाममात्र उपप्रकार सामान्य अव्यवहार्य में है। संकलक को अनंत प्रतिगमन में मजबूर करने के तरीके हैं, और सी # कंपाइलर इन्हें पहचान नहीं पाता है और अनंत यात्रा शुरू करने से पहले उन्हें रोकता है। (फिर भी। मैं Roslyn संकलक में इसके लिए पहचान जोड़ने की उम्मीद कर रहा हूं लेकिन हम देखेंगे।)

यदि यह आपकी रूचि है तो विषय पर मेरा आलेख देखें। आप लिंक किए गए पेपर को भी पढ़ना चाहेंगे।

http://blogs.msdn.com/b/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx

+0

विस्तृत उत्तर के लिए धन्यवाद। आपका ब्लॉग पोस्ट सिर पर नाखून हिट करता है। +1 यह भी इंगित करने के लिए कि सी # कंपाइलर स्पष्ट रूप से अनंत चीज़ों की बात करते समय बोर्ग सामूहिक से अधिक स्मार्ट है। :) – stakx

6

दुर्भाग्य से, वहाँ एक तरह से पूरी तरह से इसे रोकने के लिए नहीं है, और एक सामान्य ICloneable<T> कोई प्रकार की कमी के साथ पर्याप्त है। आपकी बाधा केवल कक्षाओं के लिए संभावित मानकों को सीमित करती है जो स्वयं इसे कार्यान्वित करते हैं, जिसका मतलब यह नहीं है कि वे वर्तमान में लागू किए जा रहे हैं।

दूसरे शब्दों में, अगर एक Cow औजार ICloneable<Cow>, तब भी आप आसानी से Sheep लागू ICloneable<Cow> कर देगा।

मैं बस दो कारणों के लिए बाधाओं के बिना ICloneable<T> का प्रयोग करेंगे:

  1. मैं गंभीरता से संदेह क्या तुमने कभी एक गलत प्रकार पैरामीटर का उपयोग करने का एक गलती कर देगा।

  2. इंटरफेस कोड के अन्य हिस्सों के लिए अनुबंधों के लिए हैं, ऑटोपिलोट पर कोड के लिए उपयोग नहीं किया जाना चाहिए। यदि कोड का एक हिस्सा ICloneable<Cow> की अपेक्षा करता है और आप Sheep पास करते हैं जो ऐसा कर सकता है, तो वह उस बिंदु से पूरी तरह से मान्य लगता है।

+1

+1 "[' इंटरफ़ेस एक्स जहां टी: एक्स {} '] केवल उन वर्गों के संभावित पैरामीटर को सीमित करता है जो स्वयं इसे लागू करते हैं, जिसका अर्थ यह नहीं है कि वे वर्तमान में कार्यान्वित किए जा रहे हैं।" बहुत संक्षिप्त, बकाया! –

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

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