What is the correct way to define a constant value within a derived class in order to validate a parameter in the parent constructor.
Given the following example:
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){}
}
Obviously the above does not work as expected due to the Virtual member call in constructor
(yes I understand the warning, I'm not asking about that)
In my logic (which seems to be flawed), the VertexCount
is a feature of the Polygon
class (because the fixed size of the arrays of both Edges
and Vertices
will be defined by within the Polygon class) during initialization, and varies based on the derived class (hence needs to be defined in the derived class).
The derived class NEEDS to define the value of VertexCount
because it is specific to the derived class, however, the base class isn't aware of the derived class. This is the reason for the 'abstract int', to ensure that the derived class overrides it. Also, VertexCount
is a property, because fields cannot be abstract. However, it also should be a constant (because a triangle's sides are always going to be 3 and a quadrilateral's sides are always going to be 4).
Finally, the message for the Exception
being thrown in the base constructor, should be something like:
if(vertices.Length != VertexCount)
threw new ArgumentOutOfRangeException(nameof(vertices),
message: $"A {this.ToString()} requires exactly {VertexCount} vertices, received {vertices.Length}");
Of course the 'this.ToString()' part would be called in the context of the base class rather than the derived class (maybe a reflection solution would work here)?
So with all of this, the alternative is to ditch the constructor in the base class, create a constant for the VertexCount
in the derived classes, and initialize and set all the values in the derived classes constructors. This seems like it would be a lot of duplicated code across the derived classes (maybe not in the above example because technically I'm only duplicating 2 lines of code in each, but what happens when the constructor becomes heavier).
What is the 'proper' way of doing this with the least amount of duplicated code?