153
votes

I have an abstract base class and I want to declare a field or a property that will have a different value in each class that inherits from this parent class.

I want to define it in the baseclass so I can reference it in a base class method - for example overriding ToString to say "This object is of type property/field". I have got three ways that I can see of doing this, but I was wondering - what is the best or accepted way of doing this? Newbie question, sorry.

Option 1:
Use an abstract Property and override it on the inherited classes. This benefits from being enforced (you have to override it) and it is clean. But, it feels slightly wrong to return a hard-code value rather than encapsulate a field and it is a few lines of code instead of just. I also have to declare a body for "set" but that is less important (and there is probably a way to avoid that which I am not aware of).

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

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

Option 2
I can declare a public field (or a protected field) and explicitly override it in the inherited class. The example below will give me a warning to use "new" and I can probably do that, but it feels wrong and it breaks the polymorphism, which was the whole point. Doesn't seem like a good idea...

abstract class Mother
{
    public int MyInt = 0;
}

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

Option 3
I can use a protected field and set the value in the constructor. This seems pretty tidy but relies on me ensuring the constructor always sets this and with multiple overloaded constructors there is always a chance some code path won't set the value.

abstract class Aunt
{
    protected int MyInt;
}

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

It's a bit of a theoretical question and I guess the answer has to be option 1 as it is the only safe option but I am just getting to grips with C# and wanted to ask this of people with more experience.

10
abstract public int MyInt { get; set;} => public abstract string IntentName { get; set;} :DNavid Golforoushan
@Čamo It's not appropriate to edit titles as you're doing. Tags are there to accomplish that.Servy
Language should be in title. Nobody has time to search and read little tags somewhere at the end of the question while needs to search tons of results. Thank you for understandingČamo
@Čamo And yet your personal opinion on the matter is in strict opposition to the site's policy on the matter. Just because you want everyone to put their tags in the title doesn't make it appropriate. Tags are considered when searching, not just titles. Hope these reasons make sense and thanks for your understanding in not violating site rules going forward.Servy
@Čamo If you want the policy changed the propose that the policy be changed, don't go around improperly editing questions. There are lots of lengthy discussions on the matter which you're free to read up on if you're interested in the explanations of the current policy, and which you should absolutely familiarize yourself with before proposing changing it.Servy

10 Answers

144
votes

Of the three solutions only Option 1 is polymorphic.

Fields by themselves cannot be overridden. Which is exactly why Option 2 returns the new keyword warning.

The solution to the warning is not to append the “new” keyword, but to implement Option 1.

If you need your field to be polymorphic you need to wrap it in a Property.

Option 3 is OK if you don’t need polymorphic behavior. You should remember though, that when at runtime the property MyInt is accessed, the derived class has no control on the value returned. The base class by itself is capable of returning this value.

This is how a truly polymorphic implementation of your property might look, allowing the derived classes to be in control.

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 */ }
    }
}
18
votes

Option 2 is a non-starter - you can't override fields, you can only hide them.

Personally, I'd go for option 1 every time. I try to keep fields private at all times. That's if you really need to be able to override the property at all, of course. Another option is to have a read-only property in the base class which is set from a constructor parameter:

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)
    {
    }
}

That's probably the most appropriate approach if the value doesn't change over the lifetime of the instance.

9
votes

You could do this

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; } }
}

virtual lets you get a property a body that does something and still lets sub-classes override it.

7
votes

option 2 is a bad idea. It will result in something called shadowing; Basically you have two different "MyInt" members, one in the mother, and the other in the daughter. The problem with this, is that methods that are implemented in the mother will reference the mother's "MyInt" while methods implemented in the daughter will reference the daughter's "MyInt". this can cause some serious readability issues, and confusion later down the line.

Personally, I think the best option is 3; because it provides a clear centralized value, and can be referenced internally by children without the hassle of defining their own fields -- which is the problem with option 1.

4
votes

You could define something like this:

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

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

By setting the value as readonly, it ensures that the value for that class remains unchanged for the lifetime of the object.

I suppose the next question is: why do you need it?

3
votes

If you are building a class and you want there to be a base value for the property, then use the virtual keyword in the base class. This allows you to optionally override the property.

Using your example above:

//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;
        }
    }
}

In a program:

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

I'd go with option 3, but have an abstract setMyInt method that subclasses are forced to implement. This way you won't have the problem of a derived class forgetting to set it in the constructor.

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

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

By the way, with option one, if you don't specify set; in your abstract base class property, the derived class won't have to implement it.

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

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

You can go with option 3 if you modify your abstract base class to require the property value in the constructor, you won't miss any paths. I'd really consider this option.

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

}

Of course, you then still have the option of making the field private and then, depending on the need, exposing a protected or public property getter.

0
votes

I did this...

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";
        }
    }
}

This way you can still use fields.

0
votes

The example implementation when you want to have an abstract class with implementation. Subclasses must:

  1. Parameterize the implementation of an abstract class.
  2. Fully inherit the implementation of the abstract class;
  3. Have your own implementation.

In this case, the properties that are necessary for the implementation should not be available for use except for the abstract class and its own subclass.

    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
    }