Как правильно определить постоянное значение в производном классе для проверки параметра в родительском конструкторе.
Учитывая следующий пример:
public abstract class Polygon
{
protected abstract int VertexCount { get; }
public LineSegment[] Edges { get { /* ... */ } }
public Point2D[] Vertices { get { /* ... */ } }
protected Polygon(Point2D vertices)
{
if(vertices.Length != VertexCount)
threw new ArgumentOutOfRangeException(...);
}
}
public class Triangle: Polygon
{
protected override int VertexCount { get; } = 3;
public Triangle(Point2D[] vertices) : base(vertices){}
}
public class Quadrilateral: Polygon
{
protected override int VertexCount { get; } = 4;
public Quadrilateral(Point2D[] vertices) : base(vertices){}
}
Очевидно, что вышеприведенное не работает должным образом из-за Virtual member call in constructor
(да, я понимаю предупреждение, я не спрашиваю об этом)
В моей логике (которая кажется ошибочной), VertexCount
является особенностью класса Polygon
(потому что фиксированный размер массивов как Edges
, так и Vertices
будет определяться в пределах Класс многоугольника) во время инициализации и изменяется в зависимости от производного класса (следовательно, должен быть определен в производном классе).
Производный класс НЕОБХОДИМО для определения значения VertexCount
, поскольку он специфичен для производного класса, однако базовый класс не знает о производном классе. Это причина для абстрактного int, чтобы гарантировать, что производный класс переопределяет его. Кроме того, VertexCount
является свойством, поскольку поля не могут быть абстрактными. Однако это также должно быть константой (потому что стороны треугольника всегда будут равны 3, а стороны четырехугольника всегда будут равны 4).
Наконец, сообщение для Exception
, генерируемого в базовом конструкторе, должно выглядеть примерно так:
if(vertices.Length != VertexCount)
threw new ArgumentOutOfRangeException(nameof(vertices),
message: $"A {this.ToString()} requires exactly {VertexCount} vertices, received {vertices.Length}");
Конечно, часть 'this.ToString ()' будет вызываться в контексте базового класса, а не производного класса (возможно, здесь будет работать решение с отражением)?
Таким образом, при всем этом альтернативой является отказ от конструктора в базовом классе, создание константы для VertexCount
в производных классах, а также инициализация и установка всех значений в конструкторах производных классов. Похоже, что в производных классах будет много дублированного кода (возможно, не в приведенном выше примере, потому что технически я дублирую только 2 строки кода в каждой, но что происходит, когда конструктор становится тяжелее).
Каков «правильный» способ сделать это с наименьшим количеством дублирующегося кода?