开发者

Initializing fields in inherited classes

开发者 https://www.devze.com 2022-12-15 18:01 出处:网络
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 ex开发者_Go百科plain clearly

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 ex开发者_Go百科plain 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)


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


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


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


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消