2009-09-09 7 views
6

मैं समझता हूं कि कैसे "नया" कीवर्ड व्युत्पन्न वर्ग में विधियों को छुपा सकता है। हालांकि, कक्षाओं के लिए इसका क्या प्रभाव है जो कीवर्ड का उपयोग करने वाले इंटरफेस को कार्यान्वित करते हैं?क्या आप इंटरफ़ेस पर गुणों का विस्तार करने के लिए C# नए कीवर्ड का उपयोग कर सकते हैं?

इस उदाहरण पर विचार करें, जहां मैं अपनी संपत्तियों को पढ़ने/लिखने के द्वारा एक इंटरफ़ेस का विस्तार करने का निर्णय लेता हूं।

public interface IReadOnly { 

    string Id { 
     get; 
    } 
} 

public interface ICanReadAndWrite : IReadOnly { 

    new string Id { 
     get; 
     set; 
    } 
} 

तो फिर तुम इस तरह काम करने के लिए सक्षम हैं:

public IReadOnly SomeMethod() { 
    // return an instance of ICanReadAndWrite 
} 

यह बुरा डिजाइन है? क्या यह मेरी कक्षाओं के लिए मुद्दों का कारण बनता है जो ICanReadAndWrite को लागू करते हैं?

संपादित करें:

मैं एक कारखाने वर्ग है कि एक IShoppingCartItemReadWrite देता है कहते हैं: यहाँ की एक काल्पनिक उदाहरण क्यों मैं इस तरह कुछ करने के लिए चाहते हो सकता है है। इसके बाद मैं एक सेवा परत कर सकता हूं जो उस पर कीमतों में बदलाव करता है, सामान बदलता है, आदि। फिर, मैं इन वस्तुओं को IShoppingCartItemRead के रूप में पास कर सकता हूं केवल कुछ प्रकार की प्रस्तुति परत जो उन्हें नहीं बदलेगा। (हाँ, मुझे पता है कि यह तकनीकी रूप से बदल सकता है - यह एक डिज़ाइन प्रश्न है, सुरक्षा नहीं, आदि)

+0

आपका विशिष्ट उदाहरण अधिक समझ में नहीं आता है। यदि आप पढ़ और लिख सकते हैं, तो यह पढ़ा नहीं जाता है। –

+0

एक IShoppingCartItemReadWrite बदला जा सकता है, लेकिन अगर मेरे पास ISHoppingCartItemReadOnly का संदर्भ है, तो यह केवल तब तक पढ़ा जाता है जब तक कि आप इसे किसी अन्य चीज़ पर नहीं डाल देते। – user10789

+0

ध्यान दें कि आपको वास्तव में "नए" कीवर्ड की आवश्यकता नहीं है। –

उत्तर

19

यह एक विशेष रूप से बुरा विचार नहीं है। आपको यह जानकारी होनी चाहिए कि implementor कर सकते हैं (अगर यह परोक्ष इंटरफ़ेस लागू करता है, तो एक भी पढ़ने/संपत्ति लिखने दोनों इंटरफेस को संतुष्ट कर सकते हैं) दो अलग कार्यान्वयन प्रदान करते हैं:

class Test : ICanReadAndWrite { 
    public string Id { 
     get { return "100"; } 
     set { } 
    } 
    string IReadOnly.Id { 
     get { return "10"; } 
    } 
} 

Test t = new Test(); 
Console.WriteLine(t.Id); // prints 100 
Console.WriteLine(((IReadOnly)t).Id); // prints 10 

वैसे, सामान्य, में new विरासत संशोधक कुछ भी नहीं करता है ताकि संकलक को बंद करने के लिए कहें और "आप उस सदस्य को छुपा रहे हैं" चेतावनी न दें। इसे छोड़कर संकलित कोड में कोई प्रभाव नहीं पड़ेगा।

+1

संकलक चेतावनी को शांत करने के बारे में अच्छा बिंदु! हालांकि, यह शिकायत करता है क्योंकि कक्षा परिभाषाओं के लिए ऐसा कुछ करने से वे उन तरीकों से व्यवहार कर सकते हैं जिनकी आप उम्मीद नहीं कर सकते हैं। इस विशेष मामले के लिए, मैं किसी भी अनपेक्षित व्यवहार के बारे में नहीं सोच सकता ... इसलिए सवाल। – user10789

+1

हां। बेशक चेतावनी एक कारण के लिए है। एकमात्र संभव गॉचा है, जैसा कि मैंने उत्तर में कहा था, तथ्य यह है कि आप दो अलग-अलग विधि स्लॉट से निपट रहे हैं जो विभिन्न कार्यान्वयन को हल कर सकते हैं। यह 'नया' का उपयोग करने का पछतावा है। 'इंटरफेस' के लिए यह ज्यादातर समय हानिकारक नहीं है क्योंकि वे कोई कार्यान्वयन प्रदान नहीं करते हैं और कॉलर विधि के मनमाने ढंग से कार्यान्वयन की अपेक्षा करता है। –

+1

नया कीवर्ड कंपाइलर को शांत करने के लिए नहीं है, यह स्पष्ट रूप से यह कहने के लिए है कि "मैं किसी भी सदस्य को ओवरराइड नहीं करना चाहता, मेरा इरादा इसे छाया करना है, और मैं इस तथ्य से अवगत हूं"। चेतावनी आपको "अनजाने में एक सदस्य को छिपाने" से दूर रखना है। –

0

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

+0

यह निश्चित रूप से संकलित करता है। यदि आप नया कीवर्ड नहीं जोड़ते हैं, तो आपको निम्न संकलन चेतावनी मिलती है: 'ICanReadAndWrite.Id' विरासत में सदस्य 'IReadOnly.Id' छुपाता है। छिपाने के इरादे से नए कीवर्ड का प्रयोग करें। – user10789

+0

स्पष्ट इंटरफ़ेस कार्यान्वयन के संबंध में, मुझे लगता है कि यदि आप ऐसा करते हैं, तो आईडी संपत्ति के दो पूरी तरह से अलग कार्यान्वयन ठीक वही है जो आप चाहते हैं। मुझे छुपे हुए गॉथस या कम से कम स्पष्ट समस्याओं में दिलचस्पी है जो इस दृष्टिकोण के कारण हो सकती हैं। – user10789

+1

अफसोस की बात है, बस संपत्ति के लिए एक सेटर जोड़ना काम नहीं करेगा। अगर सेटर गेटटर को छाया करता है, तो संपत्ति को पढ़ने के लिए बिना किसी छायादार गेटर के प्रकार के टाइपकास्ट की आवश्यकता होती है। अगर सेटर गेटर को छाया नहीं देता है, यानी एक स्वतंत्र गेटर और सेटर दोनों गुंजाइश में हैं, न तो सी # या vb.net के भीतर प्रयोग योग्य होगा। – supercat

1

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

0

आप इसे कर सकते हैं लेकिन मुझे यकीन नहीं है कि आप इसे करने के द्वारा क्या हासिल करने की उम्मीद कर रहे हैं।

public IReadOnly SomeMethod() { 
    // return an instance of ICanReadAndWrite 
} 

इस विधि एक IReadOnly जिसका मतलब है कि यह कोई फर्क नहीं पड़ता कि है कि आप एक ICanReadAndWrite वापस आ गए के लिए एक संदर्भ वापस आ जाएगी। क्या यह दृष्टिकोण बेहतर नहीं होगा?

public interface IReadOnly 
{ 
    String GetId(); 
} 

public interface ICanReadAndWrite : IReadOnly 
{ 
    String SetId(); 
} 
+0

मैं एक साधारण संपत्ति का उपयोग करना चाहता हूं। – user10789

7

आपको आईआरएएनआरड्राइट को इरेडऑनली के आधार पर लागू नहीं करना चाहिए, बल्कि इसके बजाय उन्हें अलग करना चाहिए।

यानी।इस तरह:

public class SomeObject : IReadOnly, ICanReadWrite 
{ 
    public string Id 
    { 
     get; 
     set; 
    } 
} 

ध्यान दें कि कक्षा में एक ही संपत्ति दोनों इंटरफेस का समर्थन कर सकते हैं:

public interface IReadOnly 
{ 
    string Id 
    { 
     get; 
    } 
} 

public interface ICanReadAndWrite 
{ 
    string Id 
    { 
     get; 
     set; 
    } 
} 

यहां कक्षा उन्हें प्रयोग है।

ध्यान दें कि टिप्पणी के अनुसार, एक मजबूत समाधान प्राप्त करने का एकमात्र तरीका एक रैपर ऑब्जेक्ट भी होगा।

दूसरे शब्दों में, यह अच्छा नहीं है:

public class SomeObject : IReadOnly, ICanReadWrite 
{ 
    public string Id 
    { 
     get; 
     set; 
    } 

    public IReadOnly AsReadOnly() 
    { 
     return this; 
    } 
} 

के रूप में फोन करने वाले सिर्फ यह कर सकते हैं:

ICanReadWrite rw = obj.AsReadOnly() as ICanReadWrite; 
rw.Id = "123"; 

एक मजबूत समाधान पाने के लिए आपको एक आवरण वस्तु की जरूरत है, इस तरह:

public class SomeObject : IReadOnly, ICanReadWrite 
{ 
    public string Id 
    { 
     get; 
     set; 
    } 

    public IReadOnly AsReadOnly() 
    { 
     return new ReadOnly(this); 
    } 
} 

public class ReadOnly : IReadOnly 
{ 
    private IReadOnly _WrappedObject; 

    public ReadOnly(IReadOnly wrappedObject) 
    { 
     _WrappedObject = wrappedObject; 
    } 

    public string Id 
    { 
     get { return _WrappedObject.Id; } 
    } 
} 

यह काम करेंगे, और मजबूत हो सकता है, ठीक बिंदु है जहां फोन करने वाले प्रतिबिंब का उपयोग करता है जब तक।

+1

लेकिन फिर आप एक आईसीएनआरएड एंड्राइट से एक आईरेड में नहीं डाले जा सकते हैं।यह बहुत उपयोगी होता है जब आपके पास कक्षा है जो पढ़ने/लिखने वाली वस्तुओं के साथ काम कर रही है, तो केवल उपभोक्ता को केवल पढ़ने-योग्य वस्तु वापस करना चाहती है। – user10789

+0

उपभोक्ता सिर्फ वापस आ सकता है। यह मजबूत नहीं है। – recursive

+1

बेशक यह मजबूत नहीं है, लेकिन अगर यह काम किया गया तो मूल समाधान भी नहीं था। लिखने योग्यता से छुटकारा पाने का एकमात्र तरीका एक रैपिंग ऑब्जेक्ट को वापस करना है जो स्पष्ट रूप से इसे रोकता है, यानी। केवल आईआरईडी केवल लागू करता है। –

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

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