views:

270

answers:

5

What's the best way to initialize constants or other fields in inherited classes? I realize there are many syntax errors in this example, but this is the best example to explain clearly what I am trying to do.

public abstract class Animal {
  public abstract const string Name; // #1
  public abstract const bool CanFly;
  public abstract double Price; // price is not const, because it can be modified

  public void Fly() {
    if (!CanFly)
      Debug.Writeln("{0}s can't fly.", Name);
    else
      Debug.Writeln("The {0} flew.", Name);
  }
}

public class Dog : Animal {
  public override const string Name = "Dog"; // #2
  public override const bool CanFly = false;
  public override double Price = 320.0;
}

public class Bird : Animal {
  public override const string Name = "Bird";
  public override const bool CanFly = true;
  public override double Price = 43.0;
}

A few things I'm trying to accomplish:

  • Base classes must assign these 3 fields.
  • Ideally I would want these initialized fields to be together at the top of the class so I can see which constants I assigned to each class and change them whenever needed.
  • The fields Name and CanFly cannot be changed.

I know that you could initialize these fields in a constructor (if you get rid of the const), but then they aren't guaranteed to be assigned. If you have these fields as properties instead and override them, you would still need to initialize the backing field of the property. How would you implement this?

A few syntax errors it complains about:

  • The modifier 'abstract' is not valid on fields. Try using a property instead. (#1)
  • A const field requires a value to be provided (#1)
  • The modifier 'override' is not valid for this item (#2)
+2  A: 

If you want to have particular fields in your abstract class, but don't want to define them in the base class, you can require that implementers supply the values through the constructor.

public abstract class MyClass
{
    private readonly double price;

    protected MyClass(double price)
    {
        this.price = price
    }
}

With such a base class, all derived classes must supply a value to the base class' constructor, or the code will not compile. Here's one example of how that might look:

public class Foo : MyClass
{
    public Foo() : base(42) { }
}
Mark Seemann
Why the downvote?
Mark Seemann
+3  A: 

If a base class requires a value to be provided by a derived class, the two most common ways are:

Require it in the constructor:

public readonly double Price;

protected BaseClass(double price)
{
    this.Price = price;
}

Derived classes must pass the price into the constructor:

public Derived() : base(32)
{
}

Or, make it an abstract property:

public abstract double Price { get; }

Derived classes must provide some way to return the value (though where they get it is up to the derived class, which in many cases provides more flexibility):

public override double Price
{
    get
    {
        return 32;
    }
}
Rex M
The potential disadvantage of an abstract property is that derived classes may break the "never changes during lifetime" guarantee, which can be enforced with readonly field + ctor.
Pavel Minaev
+1  A: 

You could use readonly and a internal constructor to enforce this behavior but it would be somewhat lacking in finese. If you go with this the inheritors would need to be in the same namespace/assembly in order to take advantage of the internal constructor.

GrayWizardx
A: 

the other model is to create an accessor (property) that is virtual. THis forces the derived classes to implement it.

THe advantage of this is that 'canfly' might have an answer that depends on the (say) time of day.

pm100
A: 

The errors you get are more or less telling you what to do. You want to use abstract properties, not fields, for Name and CanFly, while Price would be a normal property. In the derived classes, the abstract properties would be read-only and return a constant, in each case. In code:

public abstract class Animal {
  public abstract string Name { get; }
  public abstract bool CanFly { get; }
  public double Price { get; set; }
  // etc
}

public class Dog : Animal {
  public override string Name { get { return "Dog"; } }
  public override bool CanFly { get { return false; } }
  public Dog() { Price = 320.0; }
}

// etc
Gorpik