Инициализация полей в унаследованных классах - PullRequest
12 голосов
/ 09 января 2010

Как лучше всего инициализировать константы или другие поля в унаследованных классах? Я понимаю, что в этом примере много синтаксических ошибок, но это лучший пример, чтобы четко объяснить, что я пытаюсь сделать.

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

Несколько вещей, которые я пытаюсь выполнить:

  • Базовые классы должны назначить эти 3 поля.
  • В идеале я хотел бы, чтобы эти инициализированные поля были вместе в верхней части класса, чтобы я мог видеть, какие константы я назначил каждому классу, и изменять их при необходимости.
  • Поля Name и CanFly не могут быть изменены.

Я знаю, что вы можете инициализировать эти поля в конструкторе (если вы избавитесь от const), но тогда они не гарантированно будут назначены. Если вместо этого вы используете эти поля в качестве свойств и переопределяете их, вам все равно придется инициализировать вспомогательное поле свойства. Как бы вы это реализовали?

Несколько синтаксических ошибок, на которые он жалуется:

  • Модификатор 'abstract' недопустим в полях. Попробуйте вместо этого использовать свойство. (# 1)
  • В поле const необходимо указать значение (# 1)
  • Модификатор 'override' недопустим для этого элемента (# 2)

Ответы [ 5 ]

21 голосов
/ 09 января 2010

Если базовый класс требует, чтобы значение было предоставлено производным классом, два наиболее распространенных способа:

Требуется в конструкторе:

public readonly double Price;

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

Производные классы должны передавать цену в конструктор:

public Derived() : base(32)
{
}

Или сделайте его абстрактным свойством:

public abstract double Price { get; }

Производные классы должны обеспечивать некоторый способ вернуть значение (хотя, где они получают, это до производного класса, который во многих случаях обеспечивает большую гибкость):

public override double Price
{
    get
    {
        return 32;
    }
}
5 голосов
/ 09 января 2010

Если вы хотите иметь определенные поля в своем абстрактном классе, но не хотите определять их в базовом классе, вы можете потребовать, чтобы разработчики предоставили значения через конструктор.

public abstract class MyClass
{
    private readonly double price;

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

При таком базовом классе все производные классы должны предоставить значение конструктору базового класса, иначе код не будет компилироваться. Вот один пример того, как это может выглядеть:

public class Foo : MyClass
{
    public Foo() : base(42) { }
}
2 голосов
/ 09 января 2010

Ошибки, которые вы получаете, более или менее говорят вам, что делать. Вы хотите использовать абстрактные свойства, а не поля, для Name и CanFly, тогда как Price будет обычным свойством. В производных классах абстрактные свойства будут доступны только для чтения и возвращают константу в каждом случае. В коде:

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
1 голос
/ 09 января 2010

Вы можете использовать readonly и внутренний конструктор для реализации этого поведения, но это будет несколько не хватать в finese Если вы пойдете с этим, наследники должны будут находиться в одном пространстве имен / сборке, чтобы воспользоваться преимуществами внутреннего конструктора.

0 голосов
/ 09 января 2010

другая модель заключается в создании виртуального метода доступа (свойства). Это заставляет производные классы реализовать его.

Преимущество этого заключается в том, что у canfly может быть ответ, который зависит от (скажем) времени суток.

...