क्या सी # में सदस्यों को छिपाने के लिए स्पष्ट इंटरफ़ेस कार्यान्वयन का उपयोग करने की अनुमति है?


14

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

public interface IMyInterface
{
    int SomeValue { get; set; }
    int AnotherValue { get; set; }
    bool SomeFlag { get; set; }

    event EventHandler SomeValueChanged;
    event EventHandler AnotherValueChanged;
    event EventHandler SomeFlagChanged;
}

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


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

1
मैंने एक लड़के के साथ काम किया, जिसने नियमित तौर पर ऐसा किया। इसने मुझे बिल्कुल पागल कर दिया।
जोएल एथरटन

... और एकत्रीकरण का उपयोग करना शुरू करें।
मिकलाई

जवाबों:


39

हाँ, यह आम तौर पर बुरा रूप है।

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

यदि आपका IntelliSense बहुत अव्यवस्थित है, तो आपकी कक्षा बहुत बड़ी है। यदि आपकी कक्षा बहुत बड़ी है, तो यह बहुत अधिक चीजें और / या खराब तरीके से डिजाइन किए जाने की संभावना है।

अपनी समस्या को ठीक करें, अपने लक्षण को नहीं।


क्या अप्रयुक्त सदस्यों के बारे में संकलक चेतावनी को हटाने के लिए इसका उपयोग करना उचित है?
गुस्सोर

11
"अपनी समस्या को ठीक करें, अपने लक्षण को नहीं।" +1
FreeAsInBeer

11

इसका उपयोग उस सुविधा के लिए करें जिसके लिए इसका उद्देश्य था। नाम स्थान अव्यवस्था को कम करना उनमें से एक नहीं है।

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

कुछ लेखक / विशेषज्ञ इसे एक विशेषता का कीचड़ मानते हैं (विधियाँ वास्तव में प्रकार के ऑब्जेक्ट मॉडल का हिस्सा नहीं हैं)। लेकिन सभी सुविधाओं की तरह, कहीं न कहीं, किसी को इसकी आवश्यकता है।

फिर, मैं इसे छिपाने या संगठन के लिए उपयोग नहीं करूंगा । सदस्यों को अंतरंगता से छिपाने के तरीके हैं।

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

"प्रमुख लेखक / विशेषज्ञ हैं जो इसे एक विशेषता का कीचड़ मानते हैं।" कौन है? प्रस्तावित विकल्प क्या है? कम से कम एक समस्या है (यानी एक उप-संस्करण / कार्यान्वयन वर्ग में इंटरफ़ेस विधियों की विशेषज्ञता), जिसे स्पष्ट कार्यान्वयन की अनुपस्थिति में हल करने के लिए C # में कुछ अन्य सुविधा को जोड़ना होगा (ADO.NET और जेनेरिक संग्रह देखें) ।
झूमिनल

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

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

@ झोमिनल - ज़रूर, जब कुछ मिनट बाद मैं अपडेट करूंगा। धन्यवाद।
कोडेनहेम

छिपाना उन स्थितियों में पूरी तरह से उपयुक्त हो सकता है जहां एक वर्ग एक फैशन में एक इंटरफ़ेस विधि लागू कर सकता है जो इंटरफ़ेस अनुबंध का अनुपालन करता है लेकिन उपयोगी नहीं है । उदाहरण के लिए, जब मैं उन कक्षाओं के विचार को नापसंद करता हूं, जहां IDisposable.Disposeकुछ होता है, लेकिन एक अलग नाम दिया जाता है Close, तो मैं इसे पूरी तरह से उस वर्ग के लिए उचित मानूंगा, जिसका अनुबंध स्पष्ट रूप से अस्वीकार करता है कि कोड Disposeस्पष्ट इंटरफ़ेस कार्यान्वयन का उपयोग करने के लिए कॉल किए बिना इंस्टेंस बना सकता है और छोड़ सकता है। एक IDisposable.Disposeविधि परिभाषित करें जो कुछ भी नहीं करती है।
सुपरकैट

5

मैं गन्दा कोड का संकेत हो सकता हूं, लेकिन कभी-कभी वास्तविक दुनिया गड़बड़ होती है। .NET फ्रेमवर्क से एक उदाहरण ReadOnlyColection है जो म्यूटिंग सेटर [], ऐड और सेट को छुपाता है।

आईई ReadOnlyCollection लागू करता है IList <T>। कई साल पहले एसओ को मेरा प्रश्न भी देखें जब मैंने यह विचार किया था।


वैसे यह मेरा अपना इंटरफ़ेस है और मैं इसका उपयोग करूँगा, इसलिए इसे शुरू से गलत करने का कोई मतलब नहीं है।
काइल बरन

2
मैं यह नहीं कहूंगा कि यह परिवर्तनशील सेटर को छुपाता है, बल्कि यह कि यह इसे प्रदान नहीं करता है। एक बेहतर उदाहरण होगा ConcurrentDictionary, जो IDictionary<T>स्पष्ट रूप से विभिन्न सदस्यों को लागू करता है ताकि ConcurrentDictionaryए के उपभोक्ता उन्हें सीधे नहीं बुलाएंगे और बी) उन तरीकों का उपयोग कर सकते हैं जिनके लिए IDictionary<T>बिल्कुल आवश्यक होने पर कार्यान्वयन की आवश्यकता होती है। उदाहरण के लिए, उपयोगकर्ताओं को अनावश्यक अपवादों की आवश्यकता से बचने के बजाय कॉल ConcurrentDictionary<T> करना चाहिएTryAddAdd
ब्रायन

बेशक, Addस्पष्ट रूप से लागू करने से अव्यवस्था भी कम हो जाती है। TryAddकुछ भी Addकर सकते हैं ( Addएक कॉल के रूप में लागू किया जाता है TryAdd, इसलिए दोनों प्रदान करना बेमानी होगा)। हालांकि, TryAddआवश्यक रूप से एक अलग नाम / हस्ताक्षर है, इसलिए IDictionaryइस अतिरेक के बिना इसे लागू करना संभव नहीं है । स्पष्ट कार्यान्वयन इस समस्या को सफाई से हल करता है।
ब्रायन

उपभोक्ता के दृष्टिकोण से अच्छी तरह से तरीके छिपे हुए हैं।
एसेन स्कोव पेडरसन

1
आप IReadonlyCollection <T> के बारे में लिखते हैं लेकिन ReadOnlyCollection <T> से लिंक करें। एक इंटरफ़ेस में पहला, दूसरा एक वर्ग है। IReadonlyCollection <T> IList <T> लागू नहीं करता, भले ही ReadonlyCollection <T> करता है।
जोर्गन फॉग

2

ऐसा तब करना अच्छा होता है जब सदस्य संदर्भ में व्यर्थ होता है। उदाहरण के लिए, यदि आप एक आसानी से संग्रह बनाते हैं जो IList<T>किसी आंतरिक वस्तु को सौंपकर लागू करता है _wrappedतो आपके पास कुछ ऐसा हो सकता है:

public T this[int index]
{
  get
  {
     return _wrapped[index];
  }
}
T IList<T>.this[int index]
{
  get
  {
    return this[index];
  }
  set
  {
    throw new NotSupportedException("Collection is read-only.");
  }
}
public int Count
{
  get { return _wrapped.Count; }
}
bool ICollection<T>.IsReadOnly
{
  get
  {
    return true;
  }
}

यहां हमें चार अलग-अलग मामले मिले हैं।

public T this[int index]इंटरफ़ेस के बजाय हमारी कक्षा द्वारा परिभाषित किया गया है, और इसलिए निश्चित रूप से एक स्पष्ट कार्यान्वयन नहीं है, हालांकि ध्यान दें कि यह T this[int index]इंटरफ़ेस में परिभाषित रीड-राइट के समान होता है लेकिन केवल-पढ़ने के लिए होता है।

T IList<T>.this[int index]स्पष्ट है क्योंकि इसका एक हिस्सा (गेट्टर) ऊपर की संपत्ति से पूरी तरह से मेल खाता है, और दूसरा हिस्सा हमेशा एक अपवाद फेंक देगा। हालांकि इंटरफ़ेस के माध्यम से इस वर्ग के उदाहरण तक पहुंचने वाले किसी व्यक्ति के लिए, यह वर्ग के प्रकार के एक चर के माध्यम से इसका उपयोग करने वाले व्यक्ति के लिए व्यर्थ है।

इसी तरह क्योंकि bool ICollection<T>.IsReadOnlyहमेशा सही होने वाला होता है, यह कोड के लिए पूरी तरह से व्यर्थ है जो वर्ग के प्रकार के खिलाफ लिखा जाता है, लेकिन इंटरफ़ेस के प्रकार के माध्यम से इसका उपयोग करना महत्वपूर्ण हो सकता है, और इसलिए हम इसे स्पष्ट रूप से लागू करते हैं।

इसके विपरीत, public int Countस्पष्ट रूप से लागू नहीं किया जाता है क्योंकि यह संभावित रूप से किसी का उपयोग करके अपने स्वयं के प्रकार के माध्यम से हो सकता है।

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

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


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

@ टेलस्टाइन इंटरफ़ेस वास्तव में लागू किया गया है।
जॉन हन्ना

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

1
@ टेलस्टाइन ने दस्तावेज अनुबंध को पूरा किया, विशेष रूप से प्रकाश में "एक संग्रह जो केवल पढ़ा जाता है, संग्रह के निर्माण के बाद तत्वों को जोड़ने, हटाने या संशोधित करने की अनुमति नहीं देता है।" Msdn.microsoft.com/en-us/library/0cfatk9t%28v=vs.110%29.aspx
जॉन हन्ना

@ टेलस्टाइन: यदि अनुबंध में परिवर्तनशीलता शामिल है, तो इंटरफ़ेस में IsReadOnlyसंपत्ति क्यों होगी ?
निक्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.