16

Collection<T> वर्ग से ICollection<T>.IsReadOnly संपत्ति का स्पष्ट इंटरफेस कार्यान्वयन ओवरराइड करने के लिए प्रयास करते समय, मैं कुछ दस्तावेज़ों में कहा है कि स्पष्ट इंटरफेस सदस्य कार्यान्वयन क्योंकि वे इस तरह के रूप संशोधक नहीं हो सकता ओवरराइड नहीं किया जा सकता है के लिए आया था virtual या abstractMSDN पर वे स्पष्ट इंटरफ़ेस सदस्य कार्यान्वयन द्वारा बुलाए जाने वाले एक अन्य सार या वर्चुअल सदस्य को बनाकर विरासत के लिए एक स्पष्ट इंटरफ़ेस सदस्य कार्यान्वयन को कैसे उपलब्ध कराते हैं, यह निर्दिष्ट करते हैं। अभी तक कोई समस्या नहीं है।सी #: इंटरफ़ेस निर्दिष्ट द्वारा संपत्ति अधिभावी स्पष्ट

लेकिन तब मुझे आश्चर्य है: ऐसा क्यों है किसी भी स्पष्ट रूप से कार्यान्वित इंटरफ़ेस सदस्य ओवरराइड करने के लिए बस इंटरफ़ेस स्पष्ट निर्दिष्ट द्वारा सी # में संभव है?

उदाहरण के लिए, मैं एक संपत्ति और विधि के साथ इस तरह एक सरल अंतरफलक है, मान लीजिए:

public interface IMyInterface 
{ 
    bool AlwaysFalse { get; } 
    bool IsTrue(bool value); 
} 

और एक वर्ग A जो इंटरफ़ेस स्पष्ट रूप से लागू करता है, और एक विधि Test() जो अपनी ही इंटरफ़ेस कॉल है सदस्य कार्यान्वयन।

public class A : IMyInterface 
{ 
    bool IMyInterface.AlwaysFalse 
    { get { return false; } } 

    bool IMyInterface.IsTrue(bool value) 
    { return value; } 

    public bool Test() 
    { return ((IMyInterface)this).AlwaysFalse; } 
} 

आप देख सकते हैं, चार सदस्यों में से कोई भी आभासी या सार है, इसलिए जब मैं इस तरह एक वर्ग B को परिभाषित:

public class B : A 
{ 
    public bool AlwaysFalse 
    { get { return true; } } 

    public bool IsTrue(bool value) 
    { return !value; } 
} 

तो फिर तुम करने के लिए B कलाकारों का एक उदाहरण उम्मीद थी AA की तरह व्यवहार करने के लिए। और यह करता है:

A a = new A(); 
Console.WriteLine(((IMyInterface)a).AlwaysFalse); // False 
Console.WriteLine(((IMyInterface)a).IsTrue(false)); // False 
Console.WriteLine(a.Test());       // False 
A b = new B(); 
Console.WriteLine(((IMyInterface)b).AlwaysFalse); // False 
Console.WriteLine(((IMyInterface)b).IsTrue(false)); // False 
Console.WriteLine(b.Test());       // False 

अब पकड़ आता है। एक वर्ग C जो वर्ग घोषणा में एक बात को छोड़कर B का एक सटीक प्रतिलिपि है बनाएँ:

public class C : A, IMyInterface 
{ /* ... same as B ... */ } 

अब C का एक उदाहरण है, जब A लिए डाली, A की तरह व्यवहार नहीं करता है लेकिन जैसे C:

A c = new C(); 
Console.WriteLine(((IMyInterface)c).AlwaysFalse); // True 
Console.WriteLine(((IMyInterface)c).IsTrue(false)); // True 
Console.WriteLine(c.Test());       // True 

यहां तक ​​कि Test() विधि अब C में ओवरराइड विधि को कॉल करती है! ऐसा क्यों है?

+0

बहुत ही दिलचस्प सवाल! –

उत्तर

10

इसमें स्पष्ट इंटरफ़ेस कार्यान्वयन के साथ कुछ भी नहीं है; यह केवल विरासत और इंटरफ़ेस मैपिंग के सामान्य नियमों का एक परिणाम है: आप बिल्कुल देखेंगे यदि AIMyInterface के कार्यान्वयन के बजाय स्पष्ट रूप से एक अंतर्निहित प्रदान किया गया है।

  • B टाइप A से विरासत टाइप करें। कुछ भी ओवरराइड नहीं है।
    B अपने AlwaysFalse और IsTrue सदस्यों को प्रदान करता है लेकिन IMyInterface लागू करें; IMyInterface का कार्यान्वयन A से प्राप्त सदस्यों द्वारा प्रदान किया जाता है: जब B का उदाहरण IMyInterface पर डाला जाता है तो यह A प्रकार के उदाहरण के समान ही व्यवहार करता है क्योंकि A इंटरफ़ेस को लागू करने वाले सदस्यों को प्रदान कर रहा है।
  • C टाइप A से विरासत टाइप करें। फिर, कुछ भी ओवरराइड नहीं है।
    C अपनी ही AlwaysFalse और IsTrue सदस्यों प्रदान करता है लेकिन इस बार उन सदस्यों करनाIMyInterface लागू: प्रकार C का एक उदाहरण IMyInterface को डाला जाता है जब तत्कालीन C के सदस्यों A की तुलना में बल्कि इंटरफेस कार्यान्वयन प्रदान करते हैं।

क्योंकि प्रकार A औजार IMyInterface स्पष्ट रूप से संकलक चेतावनी दी है यह नहीं है कि B और C के सदस्यों A के सदस्यों छुपा रहे हैं; असल में स्पष्ट इंटरफेस कार्यान्वयन के कारण A के उन सदस्यों को पहले से ही छुपाया गया था।

आप IMyInterface लागू परोक्ष बजाय स्पष्ट रूप से तो संकलक चेतावनी दी है कि B और C के सदस्यों छुपा रहे हैं, नहीं अधिभावी, A के सदस्यों और आप आदर्श new संशोधक जब उन घोषित करने का उपयोग करना चाहिए कि करने के लिए टाइप करें A परिवर्तित हुआ है B और C में सदस्य।

भाषा विनिर्देश से कुछ प्रासंगिक बिट्स यहां दिए गए हैं। (धारा 20.4.2 और ECMA-334 spec में 20.4.4; वर्गों 13.4.4 और Microsoft C#4 spec में 13.4.6।)

20.4.2 इंटरफ़ेस मानचित्रण

एक विशेष इंटरफ़ेस के कार्यान्वयन सदस्य I.M, जहां I है इंटरफेस है, जिसमें सदस्य M घोषित किया जाता है, प्रत्येक वर्ग या struct S की जांच से निर्धारित होता है, के साथ शुरूऔर एक संदेश स्थित होने तक C, के प्रत्येक क्रमिक बेस क्लास के लिए दोहराया गया है।

20.4.4 इंटरफ़ेस फिर से कार्यान्वयन

एक वर्ग है कि एक अंतरफलक कार्यान्वयन करने की अनुमति है विरासत में आधार वर्ग सूची में शामिल फिर से लागू इंटरफ़ेस द्वारा। एक एक इंटरफ़ेस का पुन: कार्यान्वयन एक ही इंटरफ़ेस मैपिंग नियमों को प्रारंभिक इंटरफ़ेस के कार्यान्वयन के रूप में ठीक उसी इंटरफ़ेस का पालन करता है।इस प्रकार, विरासत में मिला इंटरफ़ेस मानचित्रण कोई इंटरफ़ेस मानचित्रण इंटरफ़ेस का फिर से लागू करने के लिए स्थापित किया गया पर जो भी प्रभाव पड़ता है।

+0

तो तुम कहना है कि यह तार्किक है और उम्मीद है कि किसी को किसी भी स्पष्ट इंटरफेस सदस्य के लिए एक नया कार्यान्वयन प्रदान कर सकते हैं, और सब से ऊपर, मूल वर्ग है कि नए सदस्य (एक मूल कार्यान्वयन छुपा) किसी भी अधिभावी के बिना, आभासी या कॉल करेंगे कि अमूर्त तरीकों क्या? – Virtlink

+0

यह ठीक है क्योंकि आप कर रहे हैं * नहीं * अधिभावी कि आप इस व्यवहार को देख रहे हैं: उदाहरण के लिए, 'b' प्रदान करता है एक * नई *' IsTrue' के कार्यान्वयन कि * * प्रकार से 'IsTrue' विधि पर हावी नहीं होता' A'। 'बी' टाइप करें केवल 'ए' से' IMyInterface' के कार्यान्वयन को प्राप्त करता है। यह 'A.IsTrue' विधि को लागू करने वाली' IMyInterface' इसलिए जब आप करने के लिए 'b' का एक उदाहरण डाली' IMyInterface' यह 'A.IsTrue' विधि है कि इस्तेमाल किया है। [...] – LukeH

+0

टाइप 'सी' भी' IsTrue' का एक * नया * कार्यान्वयन प्रदान करता है जो '''' प्रकार से' IsTrue' विधि को ओवरराइड नहीं करता है। लेकिन 'सी' लागू करें 'IMyInterface' लागू करें। जब आपने 'सी'' के उदाहरण को 'IMyInterface' में डाला है, तो यह भाषा विनिर्देश के नियमों के अनुसार उपयोग की गई 'सीआईएसआरयूयू' विधि है। – LukeH

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