सी # इंटरफेस। स्पष्ट कार्यान्वयन बनाम स्पष्ट कार्यान्वयन


632

C # में निहित और स्पष्ट रूप से इंटरफेस को लागू करने में क्या अंतर हैं ?

आपको कब निहित का उपयोग करना चाहिए और कब स्पष्ट का उपयोग करना चाहिए?

क्या एक या दूसरे के लिए कोई पेशेवरों और / या विपक्ष हैं?


Microsoft के आधिकारिक दिशानिर्देश (प्रथम संस्करण फ्रेमवर्क डिज़ाइन दिशानिर्देशों से ) कहते हैं कि स्पष्ट कार्यान्वयन का उपयोग करने की अनुशंसा नहीं की जाती है , क्योंकि यह कोड को अप्रत्याशित व्यवहार देता है।

मुझे लगता है कि यह दिशानिर्देश पूर्व-आईओसी-समय में बहुत वैध है , जब आप चीजों को इंटरफेस के रूप में पास नहीं करते हैं।

क्या कोई उस पहलू को भी छू सकता है?


C # इंटरफेस पर पूरा लेख पढ़ें: planetofcoders.com/c-interfaces
गौरव अग्रवाल

हां, स्पष्ट इंटरफेस से बचा जाना चाहिए और आईएसपी (इंटरफ़ेस पृथक्करण सिद्धांत) को लागू करने के लिए अधिक पेशेवर दृष्टिकोण यहां एक ही कोडप्रोजेक्ट.com
शिवप्रसाद कोईराला

जवाबों:


492

जब आप अपने वर्ग पर एक सदस्य के माध्यम से अपने इंटरफ़ेस को परिभाषित करते हैं तो निहित है। स्पष्ट है जब आप इंटरफ़ेस पर अपनी कक्षा के भीतर तरीकों को परिभाषित करते हैं। मुझे पता है कि भ्रामक लगता है लेकिन यहाँ मेरा मतलब है: के IList.CopyToरूप में कार्यान्वित किया जाएगा:

public void CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}

और स्पष्ट रूप से:

void ICollection.CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}

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

MyClass myClass = new MyClass(); // Declared as concrete class
myclass.CopyTo //invalid with explicit
((IList)myClass).CopyTo //valid with explicit.

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

मुझे यकीन है कि स्पष्ट रूप से उपयोग / न करने के और भी कारण हैं जो अन्य पोस्ट करेंगे।

प्रत्येक के पीछे उत्कृष्ट तर्क के लिए इस धागे में अगली पोस्ट देखें ।


8
मुझे पता है कि यह पोस्ट पुरानी है, लेकिन मुझे यह बहुत उपयोगी लगी - एक बात ध्यान दें कि अगर यह स्पष्ट नहीं है क्योंकि यह मेरे लिए नहीं था कि उदाहरण में निहित एक publicकीवर्ड है ... अन्यथा आपको एक त्रुटि मिलेगी
jharr100

जेफरी रिक्टर सीएलआर के माध्यम से सी # 4 एड च 13 एक उदाहरण दिखाता है जहां कास्टिंग की आवश्यकता नहीं है: आंतरिक संरचना SomeValueType: IComparable {private Int32 m_x; सार्वजनिक SomeValueType (Int32 x) {m_x = x; } public Int32 तुलना (SomeValueType अन्य) {...);} Int32 IComparable.CompareTo (ऑब्जेक्ट अन्य) {return तुलना ((SomeValueType) अन्य); }} सार्वजनिक स्थैतिक शून्य मुख्य () {SomeValueType v = new SomeValueType (0); ऑब्जेक्ट ओ = नई वस्तु (); Int32 n = v.CompareTo (v); // कोई मुक्केबाजी n = v.CompareTo (ओ); // संकलन-समय त्रुटि}
एंडी डेंट

1
आज मुझे एक दुर्लभ स्थिति का सामना करना पड़ा जो एक स्पष्ट इंटरफ़ेस के उपयोग की आवश्यकता है: एक इंटरफ़ेस बिल्डर द्वारा उत्पन्न क्षेत्र के साथ एक वर्ग जो क्षेत्र को निजी बनाता है (Xamarin iOS स्टोरीबोर्ड का उपयोग करके लक्ष्यीकरण करते हुए)। और एक इंटरफ़ेस जहां यह उस क्षेत्र को उजागर करने के लिए समझ में आता है (सार्वजनिक रूप से आसानी से)। मैं इंटरफ़ेस में गेट्टर का नाम बदल सकता था, लेकिन मौजूदा नाम ऑब्जेक्ट के लिए सबसे तार्किक नाम था। इसलिए इसके बजाय मैंने निजी क्षेत्र का उल्लेख करते हुए एक स्पष्ट कार्यान्वयन किया UISwitch IScoreRegPlayerViewCell.markerSwitch { get { return markerSwitch; } }:।
टूलमेकरसैट

1
प्रोग्रामिंग की भयावहता। खैर, अच्छी तरह से बहस!
तरल कोर

1
@ToolmakerSteve एक और स्थिति (बल्कि अधिक सामान्य) है जिसमें कम से कम एक इंटरफ़ेस सदस्य के स्पष्ट कार्यान्वयन की आवश्यकता होती है, जिसमें कई इंटरफेस हैं जो एक ही हस्ताक्षर वाले सदस्य हैं लेकिन अलग-अलग रिटर्न प्रकार हैं। के रूप में यह के साथ करता है यह, इंटरफ़ेस विरासत की वजह से भी हो सकता है IEnumerator<T>.Current, IEnumerable<T>.GetEnumerator()और ISet<T>.Add(T)एक अन्य उत्तर में इसका उल्लेख किया गया है ।
phoog

201

इंप्लसिट डेफिनेशन केवल इंटरफ़ेस द्वारा सार्वजनिक विधियों के रूप में मांगे गए तरीकों / गुणों आदि को जोड़ना होगा।

स्पष्ट परिभाषा सदस्यों को केवल तभी उजागर करने के लिए बाध्य करती है जब आप सीधे इंटरफ़ेस के साथ काम कर रहे हों, न कि अंतर्निहित कार्यान्वयन। यह ज्यादातर मामलों में पसंद किया जाता है।

  1. इंटरफ़ेस के साथ सीधे काम करके, आप स्वीकार नहीं कर रहे हैं और अंतर्निहित कार्यान्वयन के लिए अपने कोड को युग्मित कर रहे हैं।
  2. उस घटना में, जो आपके पास पहले से है, कहते हैं, एक सार्वजनिक संपत्ति का नाम आपके कोड में है और आप एक इंटरफ़ेस लागू करना चाहते हैं जिसमें एक नाम गुण भी है, इसे स्पष्ट रूप से करने से दोनों अलग-अलग रहेंगे। यहां तक ​​कि अगर वे एक ही काम कर रहे थे तो मैं अभी भी नाम संपत्ति को स्पष्ट कॉल सौंपूंगा। आप कभी नहीं जानते हैं, आप यह बदलना चाह सकते हैं कि नाम सामान्य वर्ग के लिए कैसे काम करता है और नाम कैसे, इंटरफ़ेस संपत्ति बाद में काम करता है।
  3. यदि आप एक इंटरफ़ेस को स्पष्ट रूप से लागू करते हैं तो आपकी कक्षा अब नए व्यवहारों को उजागर करती है जो केवल इंटरफ़ेस के क्लाइंट के लिए प्रासंगिक हो सकती है और इसका मतलब है कि आप अपनी कक्षाओं को पर्याप्त रूप से पर्याप्त नहीं रख रहे हैं (मेरी राय)।

2
आप यहां कुछ अच्छे बिंदु बनाते हैं। विशेष रूप से ए। मैं आमतौर पर इंटरफ़ेस वैसे भी अपनी कक्षाओं को पास करता हूं, लेकिन मैंने वास्तव में इसके बारे में कभी नहीं सोचा था कि यह परिप्रेक्ष्य है।
मैटलैंट

5
मुझे यकीन नहीं है कि मैं बिंदु सी के साथ सहमत हूं। एक कैट ऑब्जेक्ट IEitable को लागू कर सकता है लेकिन खाओ () चीज का एक मूल हिस्सा है। ऐसे मामले होंगे जब आप एक बिल्ली पर ईट () का उपयोग करना चाहते हैं जब आप IEitable इंटरफ़ेस के बजाय 'रॉ' ऑब्जेक्ट का उपयोग कर रहे हैं, नहीं?
लेजेंड लय

59
मुझे कुछ ऐसी जगहों के बारे में पता है, Catजो वास्तव IEatableमें आपत्तियों के बिना है।
हम्बर्तो

26
मैं उपरोक्त सभी के साथ पूरी तरह से असहमत हूं, और यह कहूंगा कि स्पष्ट इंटरफेस का उपयोग करना आपदा का नुस्खा है न कि उनकी परिभाषा के अनुसार OOP या OOD (बहुरूपता के बारे में मेरा जवाब देखें)
वैलेंटाइन कुजब


68

पहले से ही प्रदान किए गए उत्कृष्ट उत्तरों के अलावा, कुछ मामले हैं जहां स्पष्ट कार्यान्वयन संकलक के लिए आवश्यक है कि वह यह पता लगाने में सक्षम हो कि क्या आवश्यक है। IEnumerable<T>एक प्रमुख उदाहरण के रूप में देखें, जो संभवतः काफी बार आएगा।

यहाँ एक उदाहरण है:

public abstract class StringList : IEnumerable<string>
{
    private string[] _list = new string[] {"foo", "bar", "baz"};

    // ...

    #region IEnumerable<string> Members
    public IEnumerator<string> GetEnumerator()
    {
        foreach (string s in _list)
        { yield return s; }
    }
    #endregion

    #region IEnumerable Members
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    #endregion
}

यहाँ, IEnumerable<string>औजार IEnumerable, इसलिए हमें भी चाहिए। लेकिन हैंगिंग, सामान्य और सामान्य दोनों संस्करण दोनों एक ही विधि हस्ताक्षर के साथ कार्यों को लागू करते हैं (सी # इस के लिए वापसी के प्रकार को अनदेखा करता है)। यह पूरी तरह से कानूनी और ठीक है। संकलक कैसे उपयोग करने के लिए निर्धारित करता है? यह आपको केवल अधिक से अधिक, एक निहित परिभाषा देने के लिए मजबूर करता है, फिर इसे जो कुछ भी करना है उसे हल कर सकता है।

अर्थात।

StringList sl = new StringList();

// uses the implicit definition.
IEnumerator<string> enumerableString = sl.GetEnumerator();
// same as above, only a little more explicit.
IEnumerator<string> enumerableString2 = ((IEnumerable<string>)sl).GetEnumerator();
// returns the same as above, but via the explicit definition
IEnumerator enumerableStuff = ((IEnumerable)sl).GetEnumerator();

पुनश्च: IEnumerable कार्यों के लिए स्पष्ट परिभाषा में अप्रत्यक्ष का छोटा सा टुकड़ा क्योंकि फ़ंक्शन के अंदर कंपाइलर जानता है कि चर का वास्तविक प्रकार एक स्ट्रिंगरिस्ट है, और यही वह फ़ंक्शन कॉल को हल करता है। । NET कोर इंटरफेस में से कुछ अमूर्त की परतों को लागू करने के लिए निफ्टी थोड़ा तथ्य है कि लगता है संचित है।


5
@ टसादैक: 2 साल बाद, मैं कह सकता हूं कि "अच्छा सवाल" है। मेरे पास कोई विचार नहीं है, सिवाय इसके कि मैंने उस कोड को किसी चीज़ से कॉपी किया था जिस पर मैं काम कर रहा था abstract
मैथ्यू शारले

4
@ टसादैक, आप सही हैं, लेकिन मुझे लगता है कि मैथ्यू शार्ले की पोस्ट के ऊपर का बिंदु खो नहीं गया है।
फुकुमशरूम 3

35

सी # के माध्यम से CLR से जेफरी रिक्टर के शब्दों में
( eimi का मतलब Xplicit मैं nterface एम ethod मैं mplementation)

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

  • कोई दस्तावेज यह नहीं समझाता है कि एक प्रकार विशेष रूप से एक EIMI विधि कैसे लागू करता है, और कोई Microsoft Visual Studio IntelliSense समर्थन नहीं है।
  • इंटरफ़ेस में डाले जाने पर मूल्य प्रकार के उदाहरण बॉक्सिंग होते हैं।
  • एक EIMI को एक व्युत्पन्न प्रकार से नहीं बुलाया जा सकता है।

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

ईआईएमआई का उपयोग गैर-दृढ़ता से टाइप किए गए इंटरफ़ेस सदस्यों को बुनियादी ढांचे के इंटरफेस के कार्यान्वयन से छिपाने के लिए किया जा सकता है जैसे कि IEnumerable <T> ताकि आपका वर्ग सीधे गैर-टाइप किए गए तरीके को उजागर न करे, लेकिन वाक्यविन्यास सही है।


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

4
@Valentin क्या EIMI और IEMI के लिए खड़े हैं?
डेजीनी

स्पष्ट इंटरफ़ेस विधि कार्यान्वयन
scobi

5
-1 के लिए "आम तौर पर मैं इंटरफेस को सेमी (सबसे अच्छा) ओओपी फीचर के रूप में देखता हूं, यह विरासत प्रदान करता है, लेकिन यह वास्तविक बहुरूपता प्रदान नहीं करता है।" मैं दृढ़ता से असहमत हूँ। इसके विपरीत, इंटरफेस सभी बहुरूपता के बारे में हैं और मुख्य रूप से विरासत के बारे में नहीं हैं। वे कई वर्गीकरणों को एक प्रकार में लिखते हैं। IEMI से बचें, जब आप कर सकते हैं, और प्रतिनिधि, जैसा कि @supercat ने सुझाव दिया है, जब आप नहीं कर सकते। इंटरफेस से बचें।
अलुआन हदद

1
"एक EIMI को एक व्युत्पन्न प्रकार से नहीं बुलाया जा सकता है।" << क्या? यह सच नहीं है। यदि मैं स्पष्ट रूप से किसी प्रकार पर एक इंटरफ़ेस लागू करता हूं, तो मैं उस प्रकार से प्राप्त करता हूं, फिर भी मैं इसे विधि को कॉल करने के लिए इंटरफ़ेस में डाल सकता हूं, ठीक उसी तरह जैसे कि मुझे उस प्रकार के लिए लागू करना होगा। तो निश्चित नहीं कि आप किस बारे में बात कर रहे हैं। यहां तक ​​कि व्युत्पन्न प्रकार के भीतर, मैं स्पष्ट रूप से कार्यान्वित विधि तक पहुंचने के लिए इंटरफ़ेस में "इसे" डाल सकता हूं।
ट्राइंको

34

कारण # 1

जब मैं "कार्यान्वयन के लिए प्रोग्रामिंग" ( डिज़ाइन पैटर्न से डिज़ाइन सिद्धांत ) को हतोत्साहित करना चाहता हूं, तो मैं स्पष्ट इंटरफ़ेस कार्यान्वयन का उपयोग करता हूं ।

उदाहरण के लिए, MVP आधारित वेब एप्लिकेशन में:

public interface INavigator {
    void Redirect(string url);
}

public sealed class StandardNavigator : INavigator {
    void INavigator.Redirect(string url) {
        Response.Redirect(url);
    }
}

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

कारण # 2

एक अन्य कारण जो मैं एक स्पष्ट इंटरफ़ेस कार्यान्वयन के साथ जा सकता हूं वह एक वर्ग के "डिफ़ॉल्ट" इंटरफ़ेस क्लीनर को रखने के लिए होगा। उदाहरण के लिए, यदि मैं एक ASP.NET सर्वर नियंत्रण विकसित कर रहा था, तो मैं दो इंटरफेस चाहता हूँ:

  1. कक्षा का प्राथमिक इंटरफ़ेस, जिसका उपयोग वेब पेज डेवलपर्स द्वारा किया जाता है; तथा
  2. प्रस्तुतकर्ता द्वारा उपयोग किया जाने वाला एक "छिपा हुआ" इंटरफ़ेस जिसे मैं नियंत्रण के तर्क को संभालने के लिए विकसित करता हूं

एक सरल उदाहरण इस प्रकार है। यह एक कॉम्बो बॉक्स नियंत्रण है जो ग्राहकों को सूचीबद्ध करता है। इस उदाहरण में, वेब पेज डेवलपर सूची को पॉप्युलेट करने में रुचि नहीं रखता है; इसके बजाय, वे केवल GUID द्वारा एक ग्राहक का चयन करने या चयनित ग्राहक का GUID प्राप्त करने में सक्षम होना चाहते हैं। एक प्रस्तुतकर्ता पहले पृष्ठ लोड पर बॉक्स को पॉप्युलेट करेगा, और इस प्रस्तुतकर्ता को नियंत्रण द्वारा समझाया जाता है।

public sealed class CustomerComboBox : ComboBox, ICustomerComboBox {
    private readonly CustomerComboBoxPresenter presenter;

    public CustomerComboBox() {
        presenter = new CustomerComboBoxPresenter(this);
    }

    protected override void OnLoad() {
        if (!Page.IsPostBack) presenter.HandleFirstLoad();
    }

    // Primary interface used by web page developers
    public Guid ClientId {
        get { return new Guid(SelectedItem.Value); }
        set { SelectedItem.Value = value.ToString(); }
    }

    // "Hidden" interface used by presenter
    IEnumerable<CustomerDto> ICustomerComboBox.DataSource { set; }
}

प्रस्तुतकर्ता डेटा स्रोत को पॉप्युलेट करता है, और वेब पेज डेवलपर को इसके अस्तित्व के बारे में पता करने की आवश्यकता नहीं है।

लेकिन यह एक चांदी तोप नहीं है

मैं हमेशा स्पष्ट इंटरफ़ेस कार्यान्वयन को लागू करने की अनुशंसा नहीं करूंगा। वे सिर्फ दो उदाहरण हैं जहां वे सहायक हो सकते हैं।


19

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

/// <summary>
/// This is a Book
/// </summary>
interface IBook
{
    string Title { get; }
    string ISBN { get; }
}

/// <summary>
/// This is a Person
/// </summary>
interface IPerson
{
    string Title { get; }
    string Forename { get; }
    string Surname { get; }
}

/// <summary>
/// This is some freaky book-person.
/// </summary>
class Class1 : IBook, IPerson
{
    /// <summary>
    /// This method is shared by both Book and Person
    /// </summary>
    public string Title
    {
        get
        {
            string personTitle = "Mr";
            string bookTitle = "The Hitchhikers Guide to the Galaxy";

            // What do we do here?
            return null;
        }
    }

    #region IPerson Members

    public string Forename
    {
        get { return "Lee"; }
    }

    public string Surname
    {
        get { return "Oades"; }
    }

    #endregion

    #region IBook Members

    public string ISBN
    {
        get { return "1-904048-46-3"; }
    }

    #endregion
}

यह कोड संकलित करता है और OK चलाता है, लेकिन शीर्षक गुण साझा किया जाता है।

स्पष्ट रूप से, हम चाहते हैं कि शीर्षक का मान इस बात पर निर्भर करता है कि हम कक्षा 1 को पुस्तक या व्यक्ति के रूप में मान रहे हैं। यह तब है जब हम स्पष्ट इंटरफ़ेस का उपयोग कर सकते हैं।

string IBook.Title
{
    get
    {
        return "The Hitchhikers Guide to the Galaxy";
    }
}

string IPerson.Title
{
    get
    {
        return "Mr";
    }
}

public string Title
{
    get { return "Still shared"; }
}

ध्यान दें कि स्पष्ट इंटरफ़ेस परिभाषाएँ सार्वजनिक होने का अनुमान है - और इसलिए आप उन्हें स्पष्ट रूप से सार्वजनिक (या अन्यथा) घोषित नहीं कर सकते।

ध्यान दें कि आपके पास अभी भी "साझा" संस्करण हो सकता है (जैसा कि ऊपर दिखाया गया है), लेकिन जब तक यह संभव है, ऐसी संपत्ति का अस्तित्व संदिग्ध है। शायद इसका उपयोग शीर्षक के डिफ़ॉल्ट कार्यान्वयन के रूप में किया जा सकता है - ताकि मौजूदा कोड को Class1 को IBook या IPerson में डालने के लिए संशोधित नहीं करना पड़े।

यदि आप "साझा" (निहित) शीर्षक को परिभाषित नहीं करते हैं, तो Class1 के उपभोक्ताओं को कक्षा 1 से IBook या IPerson के उदाहरणों को स्पष्ट रूप से डालना होगा - अन्यथा कोड संकलित नहीं होगा।


16

मैं ज्यादातर समय स्पष्ट इंटरफ़ेस कार्यान्वयन का उपयोग करता हूं। यहाँ मुख्य कारण हैं।

Refactoring अधिक सुरक्षित है

इंटरफ़ेस बदलते समय, यह बेहतर है यदि कंपाइलर इसकी जांच कर सकता है। यह अंतर्निहित कार्यान्वयन के साथ कठिन है।

दो सामान्य मामले दिमाग में आते हैं:

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

  • एक इंटरफ़ेस से एक फ़ंक्शन को निकालना । अवैध रूप से लागू किए गए तरीके अचानक मृत कोड होंगे, लेकिन स्पष्ट रूप से लागू किए गए तरीकों को संकलन त्रुटि द्वारा पकड़ा जाएगा। भले ही मृत कोड आसपास रखने के लिए अच्छा है, मैं इसे समीक्षा करने और इसे बढ़ावा देने के लिए मजबूर होना चाहता हूं।

यह दुर्भाग्यपूर्ण है कि C # के पास कोई ऐसा कीवर्ड नहीं है जो हमें एक अंतर्निहित कार्यान्वयन के रूप में एक विधि को चिह्नित करने के लिए मजबूर करता है, इसलिए कंपाइलर अतिरिक्त जांच कर सकता है। वर्चुअल विधियों में 'ओवरराइड' और 'नए' के ​​आवश्यक उपयोग के कारण उपरोक्त समस्याएँ नहीं हैं।

नोट: निश्चित या शायद ही-बदलते इंटरफेस (आमतौर पर विक्रेता एपीआई के) से, यह कोई समस्या नहीं है। अपने स्वयं के इंटरफेस के लिए, हालांकि, मैं यह अनुमान नहीं लगा सकता कि वे कब / कैसे बदलेंगे।

यह स्व-दस्तावेजीकरण है

अगर मुझे एक कक्षा में 'पब्लिक बूल एक्सिक्यूट ()' दिखाई देता है, तो यह पता लगाने के लिए अतिरिक्त काम करना होगा कि यह एक इंटरफ़ेस का हिस्सा है। किसी को शायद यह कहते हुए टिप्पणी करनी होगी, या इसे अन्य इंटरफ़ेस कार्यान्वयन के समूह में डाल दिया जाएगा, सभी एक क्षेत्र या समूह टिप्पणी के तहत "आईटीस्क का कार्यान्वयन" कह सकते हैं। बेशक, यह तभी काम करता है जब ग्रुप हेडर ऑफस्क्रीन न हो।

जबकि: 'बूल ITask.Execute ()' स्पष्ट और अस्पष्ट है।

इंटरफ़ेस कार्यान्वयन का स्पष्ट पृथक्करण

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

जैसा कि मैं एक कक्षा के कोड के माध्यम से देख रहा हूं, जब मैं स्पष्ट इंटरफ़ेस कार्यान्वयन में आता हूं, तो मेरा मस्तिष्क "कोड अनुबंध" मोड में बदल जाता है। अक्सर ये कार्यान्वयन केवल अन्य तरीकों से आगे होते हैं, लेकिन कभी-कभी वे अतिरिक्त राज्य / परम चेकिंग करेंगे, आने वाले मापदंडों को बेहतर मैच की आंतरिक आवश्यकताओं के लिए, या यहां तक ​​कि संस्करण के प्रयोजनों के लिए अनुवाद भी करेंगे (यानी कई पीढ़ियों के इंटरफेस सभी सामान्य कार्यान्वयन के लिए नीचे की ओर हैं)।

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

संबंधित: जॉन द्वारा कारण 2 ऊपर

और इसी तरह

साथ ही अन्य उत्तरों में पहले ही बताए गए फायदे:

समस्या

यह सब मज़ा और खुशी नहीं है। कुछ ऐसे मामले हैं जहां मैं आरोपों के साथ रहता हूं:

  • मान प्रकार, क्योंकि इसके लिए बॉक्सिंग और निचले स्तर की आवश्यकता होगी। यह एक सख्त नियम नहीं है, और यह इंटरफ़ेस पर निर्भर करता है और इसका उपयोग कैसे करना है। IComparable? अंतर्निहित। IFormattable? शायद स्पष्ट है।
  • तुच्छ प्रणाली के इंटरफ़ेस में वे विधियाँ होती हैं जिन्हें अक्सर सीधे कहा जाता है (जैसे कि IDisposable.Dispose)।

इसके अलावा, यह कास्टिंग करने के लिए एक दर्द हो सकता है जब आप वास्तव में ठोस प्रकार करते हैं और एक स्पष्ट इंटरफ़ेस विधि को कॉल करना चाहते हैं। मैं इससे दो तरह से निपटता हूं:

  1. सार्वजनिक रूप से जोड़ें और कार्यान्वयन के लिए उनके पास इंटरफ़ेस विधियाँ हैं। आमतौर पर आंतरिक रूप से काम करते समय सरल इंटरफेस के साथ होता है।
  2. (मेरी पसंदीदा विधि) एक जोड़ें public IMyInterface I { get { return this; } }(जिसे इनलाइन होना चाहिए) और कॉल करें foo.I.InterfaceMethod()। यदि कई इंटरफेस को इस क्षमता की आवश्यकता है, तो I से परे नाम का विस्तार करें (मेरे अनुभव में यह दुर्लभ है कि मुझे इसकी आवश्यकता है)।

8

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

यदि आपका कार्यान्वयन वर्ग सार्वजनिक नहीं है, तो क्लास बनाने के लिए उपयोग की जाने वाली विधि (जो एक कारखाना या IoC कंटेनर हो सकती है ) को छोड़कर, और इंटरफ़ेस विधियों (निश्चित रूप से) को छोड़कर, तो मुझे स्पष्ट रूप से लागू करने का कोई लाभ नहीं दिखता है इंटरफेस।

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

मेरी राय में, नुकसान यह है कि आप कार्यान्वयन कोड में इंटरफ़ेस से / तक गैर-सार्वजनिक सदस्यों तक पहुंच वाले स्वयं को कास्टिंग प्रकार / पाएंगे।

कई चीजों की तरह, लाभ नुकसान (और इसके विपरीत) है। स्पष्ट रूप से लागू करने वाले इंटरफेस यह सुनिश्चित करेंगे कि आपका ठोस वर्ग कार्यान्वयन कोड उजागर न हो।


1
अच्छा जवाब, बिल। अन्य उत्तर बहुत अच्छे थे लेकिन आपने कुछ अतिरिक्त वस्तुनिष्ठ दृष्टिकोण (अपनी राय के शीर्ष पर) प्रदान किए जिससे मुझे समझ में आना आसान हो गया। अधिकांश चीजों की तरह निहितार्थ या स्पष्ट कार्यान्वयन के साथ पेशेवरों और विपक्ष हैं, इसलिए आपको अपने विशेष परिदृश्य या उपयोग-केस के लिए सबसे अच्छा उपयोग करना होगा। मैं कहूंगा कि बेहतर फिगर पाने की कोशिश करने वालों को आपके जवाब को पढ़ने से फायदा होगा।
डेनियल ईगल

6

एक अंतर्निहित इंटरफ़ेस कार्यान्वयन वह जगह है जहां आपके पास इंटरफ़ेस के समान हस्ताक्षर के साथ एक विधि है।

एक स्पष्ट इंटरफ़ेस कार्यान्वयन वह जगह है जहाँ आप स्पष्ट रूप से घोषणा करते हैं कि किस इंटरफ़ेस का संबंध किस विधि से है।

interface I1
{
    void implicitExample();
}

interface I2
{
    void explicitExample();
}


class C : I1, I2
{
    void implicitExample()
    {
        Console.WriteLine("I1.implicitExample()");
    }


    void I2.explicitExample()
    {
        Console.WriteLine("I2.explicitExample()");
    }
}

MSDN: अंतर्निहित और स्पष्ट इंटरफ़ेस कार्यान्वयन


6

प्रत्येक वर्ग का सदस्य जो एक इंटरफ़ेस को लागू करता है, एक घोषणा को निर्यात करता है जो शब्दार्थ VB.NET इंटरफ़ेस घोषणाओं के तरीके के समान है, जैसे।

Public Overridable Function Foo() As Integer Implements IFoo.Foo

हालाँकि क्लास के सदस्य का नाम अक्सर इंटरफ़ेस सदस्य से मेल खाता होगा, और क्लास का सदस्य अक्सर सार्वजनिक होगा, उनमें से किसी भी चीज़ की आवश्यकता नहीं है। कोई भी घोषणा कर सकता है:

Protected Overridable Function IFoo_Foo() As Integer Implements IFoo.Foo

जिस स्थिति में वर्ग और उसके व्युत्पन्न को नाम का उपयोग करके एक वर्ग सदस्य तक पहुंचने की अनुमति होगी IFoo_Foo, लेकिन बाहरी दुनिया केवल उस विशेष सदस्य तक ही पहुँच बना सकेगी IFoo। इस तरह का दृष्टिकोण अक्सर उन मामलों में अच्छा होता है जहां एक इंटरफ़ेस विधि में सभी कार्यान्वयनों पर व्यवहार निर्दिष्ट होगा , लेकिन केवल कुछ पर उपयोगी व्यवहार [जैसे कि केवल-पढ़ने के संग्रह के लिए निर्दिष्ट व्यवहार IList<T>.Addफेंकना है NotSupportedException]। दुर्भाग्यवश, C # में इंटरफ़ेस को लागू करने का एकमात्र उचित तरीका है:

int IFoo.Foo() { return IFoo_Foo(); }
protected virtual int IFoo_Foo() { ... real code goes here ... }

उतना अच्छा नहीं।


2

स्पष्ट इंटरफ़ेस कार्यान्वयन का एक महत्वपूर्ण उपयोग मिश्रित दृश्यता के साथ इंटरफेस को लागू करने की आवश्यकता है ।

समस्या और समाधान लेख # आंतरिक इंटरफ़ेस में अच्छी तरह से समझाया गया है ।

उदाहरण के लिए, यदि आप अनुप्रयोग परतों के बीच वस्तुओं के रिसाव को बचाना चाहते हैं, तो यह तकनीक आपको सदस्यों की विभिन्न दृश्यता को निर्दिष्ट करने की अनुमति देती है जो रिसाव का कारण बन सकती हैं।


2

पिछले जवाब क्यों स्पष्ट रूप से एक अंतरफलक को लागू सी # में हो सकता है समझाने preferrable (ज्यादातर औपचारिक कारणों से)। हालांकि, एक ऐसी स्थिति है जहां स्पष्ट कार्यान्वयन अनिवार्य है : इंटरफ़ेस के न होने पर एनकैप्सुलेशन को लीक करने से बचने के लिए public, लेकिन कार्यान्वयन वर्ग है public

// Given:
internal interface I { void M(); }

// Then explicit implementation correctly observes encapsulation of I:
// Both ((I)CExplicit).M and CExplicit.M are accessible only internally.
public class CExplicit: I { void I.M() { } }

// However, implicit implementation breaks encapsulation of I, because
// ((I)CImplicit).M is only accessible internally, while CImplicit.M is accessible publicly.
public class CImplicit: I { public void M() { } }

उपरोक्त रिसाव अपरिहार्य है, क्योंकि C # विनिर्देश के अनुसार , "सभी इंटरफ़ेस सदस्यों के पास सार्वजनिक रूप से पहुंच है।" परिणामस्वरूप, अंतर्निहित कार्यान्वयन को भी publicएक्सेस देना होगा , भले ही इंटरफ़ेस खुद ही हो internal

C # में इंप्लिक्ट इंटरफेस कार्यान्वयन एक शानदार सुविधा है। व्यवहार में, कई प्रोग्रामर इसका उपयोग हर समय / हर जगह बिना किसी विचार के करते हैं। यह सबसे अच्छे रूप में गन्दा प्रकार की सतहों की ओर जाता है और सबसे खराब तरीके से रिसाव होता है। अन्य भाषाएं, जैसे F #, इसकी अनुमति भी नहीं देती हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.