उपवर्गों में ओवरराइडिंग फ़ील्ड्स या गुण


145

मेरे पास एक सार आधार वर्ग है और मैं एक क्षेत्र या एक संपत्ति घोषित करना चाहता हूं जिसका प्रत्येक वर्ग में एक अलग मूल्य होगा जो इस मूल वर्ग से विरासत में मिला है।

मैं इसे बेसकेल्स में परिभाषित करना चाहता हूं, इसलिए मैं इसे बेस क्लास विधि में संदर्भित कर सकता हूं - उदाहरण के लिए ToString को ओवरराइड करने के लिए यह कहने के लिए कि "यह ऑब्जेक्ट टाइप प्रॉपर्टी / फील्ड का है "। मुझे तीन तरीके मिले हैं जो मैं ऐसा करने के लिए देख सकता हूं, लेकिन मैं सोच रहा था - ऐसा करने का सबसे अच्छा या स्वीकृत तरीका क्या है? नौसिखिया सवाल, क्षमा करें।

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

abstract class Father
{
    abstract public int MyInt { get; set;}
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
        set { }
    }
}

विकल्प 2
मैं एक सार्वजनिक क्षेत्र (या एक संरक्षित क्षेत्र) घोषित कर सकता हूं और विरासत में प्राप्त वर्ग में इसे स्पष्ट रूप से ओवरराइड कर सकता हूं। नीचे दिया गया उदाहरण मुझे "नया" का उपयोग करने की चेतावनी देगा और मैं शायद ऐसा कर सकता हूं, लेकिन यह गलत लगता है और यह बहुरूपता को तोड़ता है, जो पूरे बिंदु था। एक अच्छा विचार नहीं लगता ...

abstract class Mother
{
    public int MyInt = 0;
}

class Daughter : Mother
{
    public int MyInt = 1;
}

विकल्प 3
मैं एक संरक्षित क्षेत्र का उपयोग कर सकता हूं और निर्माता में मान सेट कर सकता हूं। यह काफी सुव्यवस्थित लगता है लेकिन मुझ पर निर्भर करता है कि कंस्ट्रक्टर हमेशा यह निर्धारित करता है और कई अतिभारित कंस्ट्रक्टरों के साथ हमेशा एक मौका होता है कि कुछ कोड पथ मान सेट नहीं करेगा।

abstract class Aunt
{
    protected int MyInt;
}

class Niece : Aunt
{
    public Niece()
    {
        MyInt = 1;
    }
}

यह एक सैद्धांतिक सवाल का एक सा है और मुझे लगता है कि उत्तर का विकल्प 1 होना चाहिए क्योंकि यह एकमात्र सुरक्षित विकल्प है लेकिन मैं सिर्फ C # के साथ पकड़ बना रहा हूं और अधिक अनुभव वाले लोगों से यह पूछना चाहता हूं।


सार सार्वजनिक int MyInt {मिलता है; सेट;} => सार्वजनिक सार स्ट्रिंग IntentName {get; सेट;}: डी
नवेद गोल्फोरसन

जवाबों:


136

तीन समाधान के केवल विकल्प 1 है बहुरूपी

स्वयं द्वारा फ़ील्ड ओवरराइड नहीं की जा सकती हैं। यही कारण है कि विकल्प 2 नया कीवर्ड चेतावनी लौटाता है ।

चेतावनी का समाधान "नया" कीवर्ड जोड़ना नहीं है, बल्कि विकल्प 1 को लागू करना है।

यदि आपको अपने क्षेत्र को बहुरूपी बनाने की आवश्यकता है, तो आपको इसे एक संपत्ति में लपेटने की आवश्यकता है।

विकल्प 3 ठीक है अगर आपको बहुरूपी व्यवहार की आवश्यकता नहीं है। हालांकि, आपको याद रखना चाहिए कि जब रनटाइम पर MyInt प्रॉपर्टी एक्सेस की जाती है, तो व्युत्पन्न वर्ग का लौटाए गए मूल्य पर कोई नियंत्रण नहीं होता है। स्वयं द्वारा आधार वर्ग इस मान को लौटाने में सक्षम है।

यह है कि आपकी संपत्ति का वास्तव में बहुरूपिक कार्यान्वयन कैसे दिख सकता है, जिससे व्युत्पन्न वर्ग नियंत्रण में हो सकते हैं

abstract class Parent
{
    abstract public int MyInt { get; }
}

class Father : Parent
{
    public override int MyInt
    {
        get { /* Apply formula "X" and return a value */ }
    }
}

class Mother : Parent
{
    public override int MyInt
    {
        get { /* Apply formula "Y" and return a value */ }
    }
}

153
एक तरफ के रूप में, मुझे वास्तव में लगता है कि पिता को "वाई" का फॉर्मूला लागू करना चाहिए, और माँ, तार्किक रूप से, "एक्स"।
पीटर -

4
क्या होगा यदि मैं जनक में एक डिफ़ॉल्ट कार्यान्वयन की आपूर्ति करना चाहता हूं और क्या यह सार नहीं है?
एरोन फ्रेंके

@AaronFranke हस्ताक्षर करें: सार्वजनिक वर्चुअल int MyInt {get; }
टेड बिगहम


18

विकल्प 2 एक गैर-स्टार्टर है - आप फ़ील्ड को ओवरराइड नहीं कर सकते, आप केवल उन्हें छिपा सकते हैं।

व्यक्तिगत रूप से, मैं हर बार विकल्प 1 के लिए जाऊंगा। मैं हर समय खेतों को निजी रखने की कोशिश करता हूं। यदि आपको वास्तव में संपत्ति को ओवरराइड करने में सक्षम होना है, तो निश्चित रूप से। एक अन्य विकल्प बेस क्लास में एक रीड-ओनली प्रॉपर्टी है, जो एक कंस्ट्रक्टर पैरामीटर से सेट की गई है:

abstract class Mother
{
    private readonly int myInt;
    public int MyInt { get { return myInt; } }

    protected Mother(int myInt)
    {
        this.myInt = myInt;
    }
}

class Daughter : Mother
{
    public Daughter() : base(1)
    {
    }
}

यदि उदाहरण के जीवनकाल में मूल्य नहीं बदलता है तो शायद यह सबसे उपयुक्त तरीका है।


क्या हम यह कह सकते हैं कि अब यह msdn.microsoft.com/en-us/library/9fkccyh4.aspx के आधार पर सही नहीं है । msdn लेख से पता चलता है कि आप संपत्तियों को ओवरराइड कर सकते हैं
कोडिंगबज

1
@ कोडिंगबिज: मेरा जवाब गुणों के बारे में कहां बात करता है? फील्ड्स और प्रॉपर्टीज एक ही चीज नहीं हैं।
जॉन स्कीट

@ कोडिंगबिज: (मेरा जवाब अब गुणों के बारे में बात करता है, बेशक - लेकिन यह कभी नहीं कहा कि आप उन्हें ओवरराइड नहीं कर सकते। यह कहा - और कहता है - आप खेतों को ओवरराइड नहीं कर सकते , जो अभी भी सही है।)
जॉन स्कीट

7

विकल्प 2 एक बुरा विचार है। यह छायावाद नामक चीज में परिणत होगा; मूल रूप से आपके पास दो अलग-अलग "MyInt" सदस्य हैं, एक मां में, और दूसरा बेटी में। इसके साथ समस्या यह है कि, माँ में लागू होने वाले तरीके माँ के "MyInt" का संदर्भ देंगे जबकि बेटी में लागू किए गए तरीके बेटी के "MyInt" का संदर्भ देंगे। यह कुछ गंभीर पठनीयता के मुद्दों का कारण बन सकता है, और बाद में भ्रम की स्थिति को कम कर सकता है।

व्यक्तिगत रूप से, मुझे लगता है कि सबसे अच्छा विकल्प 3 है; क्योंकि यह एक स्पष्ट केंद्रीकृत मूल्य प्रदान करता है, और अपने स्वयं के क्षेत्रों को परिभाषित करने की परेशानी के बिना बच्चों द्वारा आंतरिक रूप से संदर्भित किया जा सकता है - जो कि विकल्प 1 के साथ समस्या है।


6

आप ऐसा कर सकते हैं

class x
{
    private int _myInt;
    public virtual int myInt { get { return _myInt; } set { _myInt = value; } }
}

class y : x
{
    private int _myYInt;
    public override int myInt { get { return _myYInt; } set { _myYInt = value; } }
}

आभासी आपको एक संपत्ति देता है जो एक शरीर है जो कुछ करता है और फिर भी उप-वर्गों को इसे ओवरराइड करने देता है।


4

आप कुछ इस तरह परिभाषित कर सकते हैं:

abstract class Father
{
    //Do you need it public?
    protected readonly int MyInt;
}

class Son : Father
{
    public Son()
    {
        MyInt = 1;
    }
}

मान को आसानी से सेट करके, यह सुनिश्चित करता है कि उस वर्ग का मान वस्तु के जीवनकाल के लिए अपरिवर्तित रहे।

मुझे लगता है कि अगला सवाल यह है: आपको इसकी आवश्यकता क्यों है?


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

3

यदि आप एक वर्ग का निर्माण कर रहे हैं और आप चाहते हैं कि संपत्ति के लिए एक आधार मूल्य हो, तो virtualआधार वर्ग में कीवर्ड का उपयोग करें । यह आपको वैकल्पिक रूप से संपत्ति को ओवरराइड करने की अनुमति देता है।

ऊपर अपने उदाहरण का उपयोग करना:

//you may want to also use interfaces.
interface IFather
{
    int MyInt { get; set; }
}


public class Father : IFather
{
    //defaulting the value of this property to 1
    private int myInt = 1;

    public virtual int MyInt
    {
        get { return myInt; }
        set { myInt = value; }
    }
}

public class Son : Father
{
    public override int MyInt
    {
        get {

            //demonstrating that you can access base.properties
            //this will return 1 from the base class
            int baseInt = base.MyInt;

            //add 1 and return new value
            return baseInt + 1;
        }
        set
        {
            //sets the value of the property
            base.MyInt = value;
        }
    }
}

एक कार्यक्रम में:

Son son = new Son();
//son.MyInt will equal 2

0

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

abstract class Base 
{
 protected int myInt;
 protected abstract void setMyInt();
}

class Derived : Base 
{
 override protected void setMyInt()
 {
   myInt = 3;
 }
}

वैसे, विकल्प एक के साथ, यदि आप सेट निर्दिष्ट नहीं करते हैं; आपके सार आधार वर्ग की संपत्ति में, व्युत्पन्न वर्ग को इसे लागू नहीं करना पड़ेगा।

abstract class Father
{
    abstract public int MyInt { get; }
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
    }
}

0

आप विकल्प 3 के साथ जा सकते हैं यदि आप निर्माण में संपत्ति के मूल्य की आवश्यकता के लिए अपने सार आधार वर्ग को संशोधित करते हैं, तो आप किसी भी पथ को याद नहीं करेंगे। मैं वास्तव में इस विकल्प पर विचार करूंगा।

abstract class Aunt
{
    protected int MyInt;
    protected Aunt(int myInt)
    {
        MyInt = myInt;
    }

}

बेशक, आपके पास फिर भी क्षेत्र को निजी बनाने का विकल्प है और फिर, जरूरत के आधार पर, संरक्षित या सार्वजनिक संपत्ति पाने वाले को उजागर करना।


0

इसे मैने किया है...

namespace Core.Text.Menus
{
    public abstract class AbstractBaseClass
    {
        public string SELECT_MODEL;
        public string BROWSE_RECORDS;
        public string SETUP;
    }
}

namespace Core.Text.Menus
{
    public class English : AbstractBaseClass
    {
        public English()
        {
            base.SELECT_MODEL = "Select Model";
            base.BROWSE_RECORDS = "Browse Measurements";
            base.SETUP = "Setup Instrument";
        }
    }
}

इस तरह आप अभी भी खेतों का उपयोग कर सकते हैं।


मुझे ऐसा लगता है कि यह प्रोटोटाइप या प्रदर्शन के लिए एक तदर्थ समाधान के रूप में अच्छा है।
ज़िमानो

0

उदाहरण कार्यान्वयन जब आप कार्यान्वयन के साथ एक सार वर्ग रखना चाहते हैं। उपवर्ग:

  1. एक अमूर्त वर्ग के कार्यान्वयन को परिमाणित करें।
  2. सार वर्ग के कार्यान्वयन को पूरी तरह से विरासत में मिला;
  3. अपना खुद का कार्यान्वयन है।

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

    internal abstract class AbstractClass
    {
        //Properties for parameterization from concrete class
        protected abstract string Param1 { get; }
        protected abstract string Param2 { get; }

        //Internal fields need for manage state of object
        private string var1;
        private string var2;

        internal AbstractClass(string _var1, string _var2)
        {
            this.var1 = _var1;
            this.var2 = _var2;
        }

        internal void CalcResult()
        {
            //The result calculation uses Param1, Param2, var1, var2;
        }
    }

    internal class ConcreteClassFirst : AbstractClass
    {
        private string param1;
        private string param2;
        protected override string Param1 { get { return param1; } }
        protected override string Param2 { get { return param2; } }

        public ConcreteClassFirst(string _var1, string _var2) : base(_var1, _var2) { }

        internal void CalcParams()
        {
            //The calculation param1 and param2
        }
    }

    internal class ConcreteClassSecond : AbstractClass
    {
        private string param1;
        private string param2;

        protected override string Param1 { get { return param1; } }

        protected override string Param2 { get { return param2; } }

        public ConcreteClassSecond(string _var1, string _var2) : base(_var1, _var2) { }

        internal void CalcParams()
        {
            //The calculation param1 and param2
        }
    }

    static void Main(string[] args)
    {
        string var1_1 = "val1_1";
        string var1_2 = "val1_2";

        ConcreteClassFirst concreteClassFirst = new ConcreteClassFirst(var1_1, var1_2);
        concreteClassFirst.CalcParams();
        concreteClassFirst.CalcResult();

        string var2_1 = "val2_1";
        string var2_2 = "val2_2";

        ConcreteClassSecond concreteClassSecond = new ConcreteClassSecond(var2_1, var2_2);
        concreteClassSecond.CalcParams();
        concreteClassSecond.CalcResult();

        //Param1 and Param2 are not visible in main method
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.