एक गेटवे केवल संपत्ति को ओवरराइड करना और एक सेटर जोड़ना असंभव क्यों है? [बन्द है]


141

निम्नलिखित C # कोड की अनुमति क्यों नहीं है:

public abstract class BaseClass
{
    public abstract int Bar { get;}
}

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get { return 0; }
        set {}
    }
}

CS0546 'SolidClass.Bar.set': ओवरराइड नहीं कर सकता क्योंकि 'BaseClass.Bar' में एक अति-निर्धारित सेट एक्सेसर नहीं है


9
StackOverflow में Microsoft की ओर से प्रश्नों का उत्तर देने की सीमित क्षमता है। अपने प्रश्न पर पुनर्विचार करने पर विचार करें।
जय बज़ुजी

1
संयोग से, नेट में इस कष्टप्रद व्यवहार के लिए एक सरल उपाय एक गैर-आभासी रीड-ओनली संपत्ति है, Fooजो एक संरक्षित अमूर्त GetFooपद्धति को लपेटने के अलावा कुछ नहीं करती है । एक अमूर्त व्युत्पन्न प्रकार एक गैर-आभासी पढ़ने-लिखने वाली संपत्ति के साथ संपत्ति को छाया कर सकता है जो GetFooएक सार SetFooपद्धति के साथ उपरोक्त विधि को लपेटने के अलावा कुछ भी नहीं करता है ; एक ठोस व्युत्पन्न प्रकार उपरोक्त लेकिन आपूर्ति परिभाषाओं के लिए GetFooऔर कर सकता है SetFoo
सुपरकैट

1
बस आग में ईंधन जोड़ने के लिए, C ++ / CLI इसकी अनुमति देता है।
ymet

1
किसी संपत्ति को ओवरराइड करने पर एक एक्सेसर जोड़ने की क्षमता को सी # के भविष्य के संस्करण ( github.com/dotnet/roslyn/issues/9482 ) के बदलाव के रूप में प्रस्तावित किया गया है ।
ब्रैंडन बॉन्ड्स

1
फ्रैंक होने के लिए, यह प्रश्न अक्सर उठाया जाता है जब मौजूदा पुस्तकालय प्रकार का विस्तार करने की आवश्यकता होती है जो निम्न पैटर्न का उपयोग करता है: केवल-पढ़ने का आधार वर्ग, व्युत्पन्न म्यूटेबल क्लास। क्योंकि लाइब्रेरी पहले से ही एक खराब पैटर्न (जैसे WPF) का उपयोग करती है, इस खराब पैटर्न को हल करने की आवश्यकता उत्पन्न होती है। व्याख्यान देने से दिन के अंत में वर्कअराउंड लागू करने से किसी को नहीं बचाया जा सकता है।
रॉन्ग

जवाबों:


-4

क्योंकि बास्कलैस के लेखक ने स्पष्ट रूप से घोषित किया है कि बार को केवल पढ़ने के लिए संपत्ति होना चाहिए। यह इस अनुबंध को तोड़ने और इसे पढ़ने-लिखने के लिए व्युत्पन्न के लिए कोई मतलब नहीं है।

मैं इस एक पर Microsoft के साथ हूँ।
मान लीजिए कि मैं एक नया प्रोग्रामर हूं, जिसे बेसिकल व्युत्पत्ति के खिलाफ कोड करने के लिए कहा गया है। मैं कुछ लिखता हूं जो मानता है कि बार को नहीं लिखा जा सकता है (क्योंकि बास्कल स्पष्ट रूप से बताता है कि यह केवल एक संपत्ति है)। अब आपकी व्युत्पत्ति के साथ, मेरा कोड टूट सकता है। जैसे

public class BarProvider
{ BaseClass _source;
  Bar _currentBar;

  public void setSource(BaseClass b)
  {
    _source = b;
    _currentBar = b.Bar;
  }

  public Bar getBar()
  { return _currentBar;  }
}

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

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


94
मैं अभी भी यकीन नहीं कर रहा हूँ। यहां तक ​​कि अगर कोई स्पष्ट सेटर नहीं है, तो यह गारंटी नहीं देता है कि संपत्ति हमेशा एक ही वस्तु लौटाएगी - इसे अभी भी किसी अन्य विधि द्वारा बदला जा सकता है।
ripper234

34
इंटरफेस के लिए सच नहीं होना चाहिए, तब? आपके पास इंटरफ़ेस पर आसानी से संपत्ति हो सकती है और कार्यान्वयन प्रकार पर पढ़ / लिख सकते हैं।
इल्या रायज़ेनकोव

49
मैं असहमत हूं: आधार वर्ग ने केवल संपत्ति की घोषणा की, जिसमें कोई सेटर नहीं था; यह वैसा ही नहीं है, जैसा कि संपत्ति केवल पढ़ने के लिए है। "केवल-पढ़ें" केवल एक अर्थ है जिसे आप इसे निर्दिष्ट करते हैं। C # में बिल्‍कुल भी प्रासंगिक गारंटी नहीं है। आपके पास केवल-प्राप्त संपत्ति हो सकती है जो हर बार बदलती है, या प्राप्त / सेट की गई संपत्ति जहां सेटर फेंकता है a InvalidOperationException("This instance is read-only")
रोमन स्टार्कोव

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

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

39

मुझे लगता है कि मुख्य कारण यह है कि सिंटैक्स किसी अन्य तरीके से काम करने के लिए बहुत स्पष्ट है। यह कोड:

public override int MyProperty { get { ... } set { ... } }

यह स्पष्ट है कि दोनों getऔर setओवरराइड हैं। कोई है setतो संकलक शिकायत करता है, आधार वर्ग में। जैसे आप बेस क्लास में परिभाषित किसी विधि को ओवरराइड नहीं कर सकते, वैसे ही आप एक सेटर को भी ओवरराइड नहीं कर सकते।

आप कह सकते हैं कि संकलक को आपके इरादे का अनुमान होना चाहिए और केवल ओवरराइड को उस विधि पर लागू करना चाहिए जिसे ओवरराइड किया जा सकता है (अर्थात इस मामले में गेट्टर), लेकिन यह C # डिज़ाइन सिद्धांतों में से एक के विरुद्ध जाता है - यह कि संकलक को आपके इरादे का अनुमान नहीं लगाना चाहिए , क्योंकि यह आपके जानने के बिना गलत अनुमान लगा सकता है।

मुझे लगता है कि निम्नलिखित वाक्यविन्यास अच्छी तरह से कर सकते हैं, लेकिन जैसा कि एरिक लिपर्ट कहते हैं, इस तरह की एक मामूली सुविधा को लागू करना अभी भी प्रयास की एक बड़ी राशि है ...

public int MyProperty
{
    override get { ... }
    set { ... }
}

या, स्वत: कार्यान्वित गुणों के लिए,

public int MyProperty { override get; set; }

19

मैं आज उसी समस्या से लड़ रहा हूं और मुझे लगता है कि इसे चाहने का एक बहुत ही वैध कारण है।

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

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

interface ITest
{
    // Other stuff
    string Prop { get; }
}

// Implements other stuff
abstract class ATest : ITest
{
    abstract public string Prop { get; }
}

// This implementation of ITest needs the user to set the value of Prop
class BTest : ATest
{
    string foo = "BTest";
    public override string Prop
    {
        get { return foo; }
        set { foo = value; } // Not allowed. 'BTest.Prop.set': cannot override because 'ATest.Prop' does not have an overridable set accessor
    }
}

// This implementation of ITest generates the value for Prop itself
class CTest : ATest
{
    string foo = "CTest";
    public override string Prop
    {
        get { return foo; }
        // set; // Not needed
    }
}

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

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


2
या, मेरे मामले में, {प्राप्त करें; निजी सेट; }। मैं किसी भी अनुबंध का उल्लंघन नहीं कर रहा हूं क्योंकि सेट निजी रहता है और केवल व्युत्पन्न वर्ग से संबंधित है।
मच्येन

16

यह संभव है

tl; dr - यदि आप चाहते हैं तो आप सेटर के साथ केवल-प्राप्त विधि को ओवरराइड कर सकते हैं। यह मूल रूप से सिर्फ:

  1. एक ऐसी newसंपत्ति बनाएं जिसमें एक getऔर एक setही नाम का उपयोग किया गया हो।

  2. यदि आप कुछ और नहीं करते हैं, तो पुरानी getपद्धति को तब भी कहा जाएगा जब व्युत्पन्न वर्ग को उसके आधार प्रकार के माध्यम से बुलाया जाता है। इसे ठीक करने के लिए, एक abstractमध्यवर्ती परत जोड़ें जो overrideपुरानी getपद्धति का उपयोग करता है और इसे नई getविधि के परिणाम को वापस करने के लिए मजबूर करता है ।

यह हमें संपत्तियों को ओवरराइड करने में सक्षम बनाता है get/ setभले ही उनकी आधार परिभाषा में कोई कमी हो।

बोनस के रूप में, आप चाहें तो रिटर्न प्रकार भी बदल सकते हैं।

  • यदि आधार की परिभाषा get-only थी, तो आप अधिक व्युत्पन्न रिटर्न प्रकार का उपयोग कर सकते हैं।

  • यदि आधार की परिभाषा थी set, तो आप हमें कम व्युत्पन्न रिटर्न प्रकार दे सकते हैं।

  • यदि आधार परिभाषा पहले से ही थी get/ है set, तो:

    • यदि आप इसे बनाते हैं तो आप अधिक व्युत्पन्न रिटर्न प्रकार का उपयोग कर सकते हैं set;

    • यदि आप इसे बनाते हैं तो आप कम व्युत्पन्न रिटर्न प्रकार का उपयोग कर सकते हैं get

सभी मामलों में, आप चाहें तो एक ही रिटर्न प्रकार रख सकते हैं। नीचे दिए गए उदाहरण सादगी के लिए समान रिटर्न प्रकार का उपयोग करते हैं।

स्थिति: पहले से मौजूद मौजूदा getसंपत्ति

आपके पास कुछ वर्ग संरचना है जिसे आप संशोधित नहीं कर सकते हैं। शायद यह सिर्फ एक वर्ग है, या यह पहले से मौजूद वंशानुक्रम का पेड़ है। जो भी हो, आप setएक संपत्ति में एक विधि जोड़ना चाहते हैं, लेकिन नहीं कर सकते।

public abstract class A                     // Pre-existing class; can't modify
{
    public abstract int X { get; }          // You want a setter, but can't add it.
}
public class B : A                          // Pre-existing class; can't modify
{
    public override int X { get { return 0; } }
}

समस्या: नहीं कर सकते के साथ -only /overridegetgetset

आप overrideएक get/ setसंपत्ति के साथ चाहते हैं, लेकिन यह संकलन नहीं करेगा।

public class C : B
{
    private int _x;
    public override int X
    {
        get { return _x; }
        set { _x = value; }   //  Won't compile
    }
}

समाधान: एक abstractमध्यवर्ती परत का उपयोग करें

जब आप सीधे overrideएक get/ setसंपत्ति के साथ नहीं कर सकते , तो आप कर सकते हैं :

  1. एक ही नाम से एक new get/ setसंपत्ति बनाएँ ।

  2. overrideसंगति सुनिश्चित getकरने के लिए नई getविधि के लिए एक सहायक के साथ पुरानी विधि ।

तो, पहले आप abstractमध्यवर्ती परत लिखते हैं :

public abstract class C : B
{
    //  Seal off the old getter.  From now on, its only job
    //  is to alias the new getter in the base classes.
    public sealed override int X { get { return this.XGetter; }  }
    protected abstract int XGetter { get; }
}

फिर, आप उस वर्ग को लिखते हैं जो पहले संकलित नहीं किया गया था। यह इस बार संकलित करेगा क्योंकि आप वास्तव में override' getएन-प्रॉपर्टी ' नहीं कर रहे हैं; इसके बजाय, आप इसे newकीवर्ड का उपयोग करके बदल रहे हैं ।

public class D : C
{
    private int _x;
    public new virtual int X { get { return this._x; } set { this._x = value; } }

    //  Ensure base classes (A,B,C) use the new get method.
    protected sealed override int XGetter { get { return this.X; } }
}

परिणाम: सब कुछ काम करता है!

जाहिर है, इस काम के लिए के रूप में इरादा है D

var test = new D();
Print(test.X);      // Prints "0", the default value of an int.

test.X = 7;
Print(test.X);      // Prints "7", as intended.

सब कुछ अभी भी काम करता है, जब Dइसका आधार कक्षाओं में से एक के रूप में देखा जाता है, जैसे Aया B। लेकिन, यह क्यों काम करता है इसका कारण थोड़ा कम स्पष्ट हो सकता है।

var test = new D() as B;
//test.X = 7;       // This won't compile, because test looks like a B,
                    // and B still doesn't provide a visible setter.

हालाँकि, बेस क्लास की परिभाषा getअभी भी अंततः व्युत्पन्न वर्ग की परिभाषा से ओवरराइड है get, इसलिए यह अभी भी पूरी तरह से सुसंगत है।

var test = new D();
Print(test.X);      // Prints "0", the default value of an int.

var baseTest = test as A;
Print(test.X);      // Prints "7", as intended.

विचार-विमर्श

यह विधि आपको -only गुणों के लिए setतरीकों को जोड़ने की अनुमति देती है get। आप इसका उपयोग सामान की तरह करने के लिए भी कर सकते हैं:

  1. किसी भी संपत्ति को एक getएकल वर्ग में बदलें , चाहे वह set, या get-और- setसंपत्ति, चाहे वह किसी आधार वर्ग में हो।

  2. व्युत्पन्न वर्गों में एक विधि का वापसी प्रकार बदलें।

मुख्य कमियां यह हैं कि करने के लिए अधिक कोडिंग है और abstract classविरासत के पेड़ में एक अतिरिक्त है। यह उन कंस्ट्रक्टरों के लिए थोड़ा कष्टप्रद हो सकता है जो पैरामीटर लेते हैं क्योंकि उन्हें मध्यवर्ती परत में कॉपी / पेस्ट करना पड़ता है।


यह अपना सवाल दिया: stackoverflow.com/questions/22210971
Nat

अच्छा तरीका (+1)। मुझे संदेह है कि क्या यह इकाई ढांचे के साथ आसानी से काम करेगा।
माइक डी किलक

9

मैं मानता हूं कि एक व्युत्पन्न प्रकार में एक गेटर को ओवरराइड करने में सक्षम नहीं होना एक विरोधी पैटर्न है। पढ़ें-केवल कार्यान्वयन की कमी को निर्दिष्ट करता है, न कि शुद्ध कार्यात्मक (शीर्ष वोट उत्तर द्वारा निहित) का अनुबंध।

मुझे संदेह है कि Microsoft की यह सीमा या तो थी क्योंकि उसी गलत धारणा को बढ़ावा दिया गया था, या शायद व्याकरण को सरल बनाने के कारण; हालाँकि, अब उस दायरे को व्यक्तिगत रूप से प्राप्त करने या निर्धारित करने के लिए लागू किया जा सकता है, शायद हम उम्मीद कर सकते हैं कि ओवरराइड भी हो सकती है।

शीर्ष वोट उत्तर द्वारा इंगित गलत धारणा, कि केवल पढ़ने / लिखने की संपत्ति की तुलना में एक पढ़ने-योग्य संपत्ति किसी तरह अधिक "शुद्ध" होनी चाहिए, हास्यास्पद है। बस रूपरेखा में कई सामान्य पढ़े गए गुणों को देखें; मान एक स्थिर / विशुद्ध रूप से कार्यात्मक नहीं है; उदाहरण के लिए, DateTime.Now केवल-पढ़ने के लिए है, लेकिन कुछ भी लेकिन एक शुद्ध कार्यात्मक मूल्य है। अगली बार जोखिम भरा है, यह मानते हुए कि यह मान लौटाएगा केवल पढ़ी गई संपत्ति का एक मूल्य 'कैश' करने का प्रयास।

किसी भी मामले में, मैंने इस सीमा को पार करने के लिए निम्नलिखित रणनीतियों में से एक का उपयोग किया है; दोनों परिपूर्ण से कम हैं, लेकिन आपको इस भाषा की कमी से परे रहने की अनुमति देगा:

   class BaseType
   {
      public virtual T LastRequest { get {...} }
   }

   class DerivedTypeStrategy1
   {
      /// get or set the value returned by the LastRequest property.
      public bool T LastRequestValue { get; set; }

      public override T LastRequest { get { return LastRequestValue; } }
   }

   class DerivedTypeStrategy2
   {
      /// set the value returned by the LastRequest property.
      public bool SetLastRequest( T value ) { this._x = value; }

      public override T LastRequest { get { return _x; } }

      private bool _x;
   }

DateTime.Now विशुद्ध रूप से कार्यात्मक है, इसमें कोई साइड-इफेक्ट नहीं है (तथ्य यह है कि निष्पादित करने के लिए समय लगता है, संभवत: एक साइड-इफेक्ट कहा जा सकता है, लेकिन निष्पादन के समय से - कम से कम जब बाध्य और संक्षिप्त - विचार नहीं किया जाता है किसी भी अन्य विधि का एक साइड-इफ़ेक्ट, मैं इसे यहाँ एक भी नहीं मानता)।
सुपरकैट

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

आप सही हैं कि मेरी शब्दावली अभेद्य थी, लेकिन मुझे लगता है कि किसी विधि के बजाय केवल पढ़ने-योग्य संपत्ति होने के कारण कुछ की उपयुक्तता शुद्धता के बजाय दुष्प्रभाव की कमी पर निर्भर है।
सुपरकैट

2

आप शायद एक नई संपत्ति बनाकर समस्या के आसपास जा सकते हैं:

public new int Bar 
{            
    get { return 0; }
    set {}        
}

int IBase.Bar { 
  get { return Bar; }
}

4
लेकिन आप इसे केवल इंटरफ़ेस लागू करते समय कर सकते हैं, न कि बेस क्लास से विरासत में मिलने पर। आपको दूसरा नाम चुनना होगा।
11'11

मुझे लगता है कि उदाहरण के तौर पर क्लास इलेबस (पब्लिक इंटरफेस IBase {int Bar {get;}}) जैसा है, अन्यथा क्लास को लागू करने में, int IBase.Bar {...} की अनुमति नहीं है। फिर आप बस एक नियमित प्रॉपर्टी बार बना सकते हैं, जिसमें दोनों मिल सकते हैं और सेट कर सकते हैं, अंत में इंटरफेस से बार प्रॉपर्टी को सेट की आवश्यकता नहीं है।
इब्राहीम बेन सलाह

1

मैं आपके सभी बिंदुओं को समझ सकता हूं, लेकिन प्रभावी रूप से, C # 3.0 के स्वचालित गुण उस मामले में बेकार हो जाते हैं।

आप ऐसा कुछ नहीं कर सकते:

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get;
        private set;
    }
}

IMO, C # को ऐसे परिदृश्य को प्रतिबंधित नहीं करना चाहिए। इसके अनुसार उपयोग करना डेवलपर की जिम्मेदारी है।


मैं आपकी बात नहीं समझता। क्या आप इस बात पर सहमत हैं कि C # को एक सेटर को जोड़ने की अनुमति देनी चाहिए, या क्या आप इस सवाल का जवाब देने वाले अधिकांश लोगों के साथ हैं?
15:23

2
जैसा कि मैंने कहा, IMO, C # को सेटर जोड़ने की अनुमति देनी चाहिए। इसके अनुसार उपयोग करना डेवलपर की जिम्मेदारी है।
बजे थॉमस डेनकर

1

समस्या यह है कि जिस कारण से Microsoft ने निर्णय लिया कि तीन अलग-अलग प्रकार के गुण होने चाहिए: केवल पढ़ने के लिए, केवल लिखने के लिए, और पढ़ने-लिखने के लिए, जिनमें से केवल एक दिए गए संदर्भ में दिए गए हस्ताक्षर के साथ मौजूद हो सकता है; संपत्तियों को केवल घोषित रूप से घोषित संपत्तियों द्वारा ओवरराइड किया जा सकता है। आप जो चाहते हैं, उसे करने के लिए एक ही नाम और हस्ताक्षर के साथ दो गुण बनाना आवश्यक होगा - जिनमें से एक केवल-पढ़ने के लिए था, और जिसमें से एक पढ़ा-लिखा था।

व्यक्तिगत रूप से, मैं चाहता हूं कि "संपत्तियों" की पूरी अवधारणा को समाप्त कर दिया जाए, सिवाय इसके कि संपत्ति-ईश सिंटैक्स को "गेट" और "सेट" विधियों को कॉल करने के लिए सिंटैक्टिक चीनी के रूप में इस्तेमाल किया जा सकता है। यह न केवल set ऐड सेट ’विकल्प की सुविधा प्रदान करेगा, बल्कि to सेट’ से a सेट ’के लिए एक अलग प्रकार लौटाने की भी अनुमति देगा। हालांकि इस तरह की क्षमता का उपयोग बहुत बार नहीं किया जाता है, लेकिन कभी-कभी यह एक रैपर ऑब्जेक्ट को वापस करने के लिए एक 'गेट' विधि के लिए उपयोगी हो सकता है, जबकि 'सेट' किसी रैपर या वास्तविक डेटा को स्वीकार कर सकता है।


0

प्रतिबिंब का उपयोग करके इसे प्राप्त करने के लिए यहां एक काम-काज है:

var UpdatedGiftItem = // object value to update;

foreach (var proInfo in UpdatedGiftItem.GetType().GetProperties())
{
    var updatedValue = proInfo.GetValue(UpdatedGiftItem, null);
    var targetpropInfo = this.GiftItem.GetType().GetProperty(proInfo.Name);
    targetpropInfo.SetValue(this.GiftItem, updatedValue,null);
}

इस तरह हम एक संपत्ति पर वस्तु मूल्य निर्धारित कर सकते हैं जो आसानी से है। हालांकि सभी परिदृश्यों में काम नहीं हो सकता है!


1
क्या आप सुनिश्चित हैं कि आप एक सेटर को प्रतिबिंब के माध्यम से कॉल कर सकते हैं जो मौजूद नहीं है (जैसा कि वर्णित गेट-ओनली गुणों में होता है)?
या मैपर

0

आपको अपने प्रश्न शीर्षक को या तो विस्तार से बदलना चाहिए कि आपका प्रश्न केवल एक अमूर्त संपत्ति को ओवरराइड करने के संबंध में है, या यह कि आपका प्रश्न आम तौर पर एक वर्ग की प्राप्त संपत्ति को अधिलेखित करने के संबंध में है।


यदि पूर्व (एक अमूर्त संपत्ति से अधिक)

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

public int GetBar(){}

लेकिन अगर आपका उस पर कोई नियंत्रण नहीं है, और बेस क्लास की कार्यक्षमता अपनी स्वयं की सार्वजनिक संपत्ति (अजीब) से पढ़ती है, तो बस यह करें:

public abstract class BaseClass
{
    public abstract int Bar { get; }
}

public class ConcreteClass : BaseClass
{
    private int _bar;
    public override int Bar
    {
        get { return _bar; }
    }
    public void SetBar(int value)
    {
        _bar = value;
    }
}

मैं (अजीब) टिप्पणी को इंगित करना चाहता हूं: मैं कहूंगा कि एक सर्वोत्तम अभ्यास एक वर्ग के लिए है कि वह अपने स्वयं के सार्वजनिक गुणों का उपयोग न करें, लेकिन जब वे मौजूद हों तो अपने निजी / संरक्षित क्षेत्रों का उपयोग करें। तो यह एक बेहतर पैटर्न है:

public abstract class BaseClass {
    protected int _bar;
    public int Bar { get { return _bar; } }
    protected void DoBaseStuff()
    {
        SetBar();
        //Do something with _bar;
    }
    protected abstract void SetBar();
}

public class ConcreteClass : BaseClass {
    protected override void SetBar() { _bar = 5; }
}

यदि बाद वाला (किसी वर्ग की केवल संपत्ति को अधिग्रहित करता है)

प्रत्येक गैर-अमूर्त संपत्ति में एक सेटर है। अन्यथा यह बेकार है और आपको इसका उपयोग करने की परवाह नहीं करनी चाहिए। Microsoft को वह करने की अनुमति नहीं है जो आप चाहते हैं। कारण होने के नाते: सेटर किसी न किसी रूप में मौजूद होता है, और आप जो चाहते हैं उसे आसानी से पूरा कर सकते हैं।

बेस क्लास, या कोई भी वर्ग जहाँ आप किसी प्रॉपर्टी को पढ़ सकते हैं {get;}, उस प्रॉपर्टी के लिए कुछ प्रकार के एक्सपोजर सेटर हैं। मेटाडेटा इस तरह दिखेगा:

public abstract class BaseClass
{
    public int Bar { get; }
}

लेकिन कार्यान्वयन में जटिलता के स्पेक्ट्रम के दो छोर होंगे:

कम से कम परिसर:

public abstract class BaseClass
{
    private int _bar;
    public int Bar { 
        get{
            return _bar;
        }}
    public void SetBar(int value) { _bar = value; }
}

सबसे जटिल:

public abstract class BaseClass
{
    private int _foo;
    private int _baz;
    private int _wtf;
    private int _kthx;
    private int _lawl;

    public int Bar
    {
        get { return _foo * _baz + _kthx; }
    }
    public bool TryDoSomethingBaz(MyEnum whatever, int input)
    {
        switch (whatever)
        {
            case MyEnum.lol:
                _baz = _lawl + input;
                return true;
            case MyEnum.wtf:
                _baz = _wtf * input;
                break;
        }
        return false;
    }
    public void TryBlowThingsUp(DateTime when)
    {
        //Some Crazy Madeup Code
        _kthx = DaysSinceEaster(when);
    }
    public int DaysSinceEaster(DateTime when)
    {
        return 2; //<-- calculations
    }
}
public enum MyEnum
{
    lol,
    wtf,
}

मेरी बात, किसी भी तरह से, आपके पास सेटर उजागर है। आपके मामले में, आप ओवरराइड करना चाह सकते हैं int Barक्योंकि आप नहीं चाहते कि आधार वर्ग इसे संभाल सके, इसकी समीक्षा करने के लिए इसे एक्सेस न करें कि यह कैसे संभाल रहा है, या आपकी इच्छा के विरुद्ध कुछ कोड वास्तविक क्विक'एनडीईएक्स को hax करने का काम सौंपा गया। ।

लैटर और पूर्व (निष्कर्ष) दोनों में

Long-Story Short: Microsoft के लिए कुछ भी बदलना आवश्यक नहीं है। आप चुन सकते हैं कि आपका कार्यान्वयन वर्ग कैसे सेट किया गया है और, निर्माणकर्ता को बैठाता है, आधार वर्ग के सभी या किसी को भी उपयोग नहीं करता है।


0

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

public abstract class BaseClass
{
    public abstract int Bar { get; }
}

public class ConcreteClass : BaseClass
{
    public override int Bar { get; }

    public ConcreteClass(int bar)
    {
        Bar = bar;
    }
}

-1

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


1
-1: एक सेटर के पास स्वचालित रूप से किसी भी हमलावर को तोड़ने के लिए एक वंशज सक्षम नहीं होता है। सेटर अभी भी केवल उन चीजों को बदल सकता है जो पहले से ही वंशज द्वारा परिवर्तनशील हैं।
रोमन स्टार्कोव

@RomanStarkov यह सच है। लेकिन इस पोस्ट का सवाल है; आप एक एब्सट्रैक्ट के लिए एक सेटर नहीं जोड़ सकते जो आपको अनुबंध नहीं करता है। विपरीत टिप्पणी में आपकी टिप्पणी उचित होगी; अगर वंशज का अपने निजी क्षेत्रों पर पूर्ण नियंत्रण हो, तो Microsoft आपको एक अमूर्त में ReadOnly संपत्ति बनाने की अनुमति क्यों देता है?
सुमेरे

+1: यह प्रश्न इस बारे में है कि Microsoft आपको अनुबंध तोड़ने की अनुमति क्यों नहीं देता है। यद्यपि आपके डाउनवोट्स का कारण इस बारे में अधिक है कि Microsoft केवल एक अनुबंध को आसानी से शामिल करने की अनुमति क्यों देता है। अतः यह उत्तर संदर्भ में सही है।
सुमेरे

@ अनुबंध में यह उल्लेख नहीं है कि संपत्ति को बदला नहीं जा सकता है। यह सब बताता है कि एक संपत्ति मौजूद है जिसे पढ़ा जा सकता है। सेटर जोड़ने से यह अनुबंध नहीं टूटेगा। आप इसे केवल-पढ़ने के लिए संपत्ति बनाने के इरादे के रूप में व्याख्या कर सकते हैं, लेकिन आप C # 6 में गारंटी नहीं दे सकते कि इसे बदलने का कोई तरीका नहीं है, इसलिए आप जिस अनुबंध के बारे में सोच रहे हैं वह वास्तव में नहीं है। एक इंटरफ़ेस के बारे में सोचें: यह एक गेटएब पर अनुबंध की पेशकश कर सकता है (केवल-प्राप्त नहीं!) संपत्ति। यह इंटरफ़ेस ठीक-ठाक प्रॉपर्टी द्वारा लागू किया जा सकता है।
1848 में रोमन स्टार्कोव

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

-1

यह असंभव नहीं है। आपको बस अपनी संपत्ति में "नया" कीवर्ड का उपयोग करना होगा। उदाहरण के लिए,

namespace {
    public class Base {
        private int _baseProperty = 0;

        public virtual int BaseProperty {
            get {
                return _baseProperty;
            }
        }

    }

    public class Test : Base {
        private int _testBaseProperty = 5;

        public new int BaseProperty {
            get {
                return _testBaseProperty;
            }
            set {
                _testBaseProperty = value;
            }
        }
    }
}

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

उम्मीद है की यह मदद करेगा


29
यह उत्तर गलत है क्योंकि चिह्नित की गई संपत्ति newअब आभासी आधार को ओवरराइड नहीं करती है। विशेष रूप से, यदि आधार संपत्ति सार है , जैसा कि मूल पोस्ट में है, तो newगैर-सार उपवर्ग में कीवर्ड का उपयोग करना असंभव है क्योंकि आपको सभी सार सदस्यों को ओवरराइड करना होगा।
तैम्वी

यह अभूतपूर्व रूप से खतरनाक है क्योंकि निम्न रिटर्न एक ही वस्तु होने के बावजूद अलग-अलग परिणाम Test t = new Test(); Base b = t; Console.WriteLine(t.BaseProperty)देता है : आपको 5 Console.WriteLine(b.BaseProperty)देता है , आपको 0 देता है, और जब आपके उत्तराधिकारी को यह डिबग करना है तो आप बेहतर दूर, बहुत दूर चले गए हैं।
मार्क सोउल

मैं w / मार्क से सहमत हूं, यह बेहद बुरा है। यदि दोनों BaseProperty कार्यान्वयन समान चर द्वारा समर्थित थे तो यह IMHO हालांकि ठीक होगा। IE: _baseProperty को संरक्षित करें और _testBaseProperty को समाप्त करें। इसके अलावा, AFAIK बेस में कार्यान्वयन आभासी होने की आवश्यकता नहीं है क्योंकि आप वास्तव में इसे ओवरराइड नहीं कर रहे हैं।
स्टीफी

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

-1

बेस क्लास में एक रीड-ओनली प्रॉपर्टी बताती है कि यह प्रॉपर्टी एक ऐसी वैल्यू को दर्शाती है, जो हमेशा क्लास के अंदर से निर्धारित की जा सकती है (उदाहरण के लिए किसी ऑब्जेक्ट के कॉन्टेस्ट से मेल खाते हुए एन्युम वैल्यू)। तो मूल्य निर्धारित करने की जिम्मेदारी कक्षा के भीतर रहती है।

एक सेटर जोड़ने से यहाँ एक अजीब समस्या पैदा होगी: यदि आप पहले से मौजूद एकल संभव मान के अलावा किसी और चीज़ के लिए मान सेट करते हैं तो एक सत्यापन त्रुटि हो सकती है।

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

इस तरह की परिस्थितियों में मेरा समाधान केवल संपत्ति को पढ़ने के लिए छोड़ना होगा और अपवाद का समर्थन करने के लिए व्युत्पन्न वर्ग में एक नया पढ़ने-लिखने की संपत्ति जोड़ना होगा। मूल संपत्ति का ओवरराइड केवल नई संपत्ति के मूल्य को वापस कर देगा। नई संपत्ति में एक उचित नाम हो सकता है जो इस अपवाद के संदर्भ को ठीक से दर्शाता है।

यह वैध टिप्पणी का भी समर्थन करता है: "गिशु द्वारा फसल के लिए गलतफहमी के लिए इसे यथासंभव कठिन बनाएं"।


1
कोई भद्दापन एक से गर्भित किया जाएगा ReadableMatrixवर्ग उपप्रकार होने (एक दो तर्क केवल पढ़ने के लिए अनुक्रमित संपत्ति के साथ) ImmutableMatrixऔर MutableMatrix। कोड जिसे केवल एक मैट्रिक्स को पढ़ने की आवश्यकता है, और यह ध्यान नहीं रखता है कि भविष्य में कुछ समय बदल सकता है, प्रकार के एक पैरामीटर को स्वीकार कर सकता है ReadableMatrixऔर पारस्परिक या अपरिवर्तनीय उपप्रकारों के साथ पूरी तरह से खुश हो सकता है।
सुपरकैट

एक अतिरिक्त सेटर कक्षा के भीतर एक निजी चर को संशोधित कर सकता है। बेस क्लास से तथाकथित "केवल पढ़ने के लिए" संपत्ति तब भी "वर्ग के भीतर से" (नए निजी चर को पढ़कर) मूल्य निर्धारित करेगी। मैं इस मुद्दे को वहाँ नहीं देखता। इसके अलावा, उदाहरण के लिए, List<T>.Countयह क्या देखता है: इसे सौंपा नहीं जा सकता है, लेकिन इसका मतलब यह नहीं है कि यह "केवल पढ़ने के लिए" है, इसे कक्षा के उपयोगकर्ताओं द्वारा संशोधित नहीं किया जा सकता है। सूची आइटमों को जोड़कर और हटाकर, इसे अप्रत्यक्ष रूप से संशोधित किया जा सकता है।
या मैपर

-2

क्योंकि IL स्तर पर, एक पठन / लेखन संपत्ति दो (गेट्टर और सेटर) तरीकों में तब्दील हो जाती है।

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

सच है, एक नई पद्धति को जोड़ना प्रति से अधिक संगतता को तोड़ना नहीं होगा, लेकिन चूंकि यह छिपी रहेगी, इसलिए इसे अस्वीकार करने का निर्णय सही अर्थ बनाता है।


2
मुझे यहाँ "बाहरी दुनिया" की ज्यादा परवाह नहीं है। मैं एक वर्ग में कार्यक्षमता जोड़ना चाहता हूं, जो हमेशा केवल उस कोड के लिए दिखाई देता है जो विशिष्ट वर्ग को जानता है और आधार को नहीं।
ripper234

@ ripper234 मैट बोल्ट का जवाब देखें: यदि आप नई संपत्ति को केवल उसी वर्ग के उपयोगकर्ताओं के लिए दृश्यमान बनाना चाहते हैं जो आपको newइसके बजाय चाहिए override
डैन बेरिंडी

1
यह छिपा नहीं रहता। आप कह रहे हैं कि आप एक नई पद्धति को बाल-वर्ग में नहीं जोड़ सकते क्योंकि नई पद्धति "बाहरी दुनिया से छिपी रहेगी" है। बेशक यह बेस-क्लास के नजरिए से छिपा हुआ है, लेकिन यह चाइल्ड क्लास के क्लाइंट्स के लिए सुलभ है। (इस बात को प्रभावित करने के लिए कि क्या करने वाले को वापस लौटना चाहिए)
भेड़ का बच्चा

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

-2

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


ऊपर वोट दें। यह बहुत ही सक्सेजफुल है। Microsoft को आधार वर्ग के उपभोक्ता को अनुबंध तोड़ने की अनुमति क्यों देनी चाहिए? मैं अपने बहुत लंबे-लंबे और भ्रमित करने वाले उत्तर के इस बहुत छोटे संस्करण से सहमत हूं। जबरदस्त हंसी। यदि आप बेस क्लास के उपभोक्ता हैं, तो आपको अनुबंध को तोड़ना नहीं चाहिए, लेकिन आप इसे कुछ अलग तरीकों से लागू कर सकते हैं।
सुमेरे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.