I want to have class which will have an indexer and number of fields like in the following example:
public abstract class ARecord
{
public abstract double this[int index] { get; }
public abstract int NumberOfFields { get; }
}
public class Record : ARecord
{
public double Field1{ get; private set; }
public double Field2{ get; private set; }
public override int NumberOfFields { get { return 2; } }
public Record(double[] records)
{
if (records.Count() != NumberOfFields) // PROBLEM IS HERE. WHEN CALLING THIS FROM DERIVED CLASS NumberOfFields=3!
throw new ArgumentException();
this.Field1= records[0];
this.Field2 = records[1];
}
public override double this[int index]
{
get { throw new NotImplementedException(); }
}
}
public class ChildRecord : Record
{
public double Field3 { get; private set; }
public override int NumberOfFields { get { return 3; } }
public ChildRecord(double[] records)
: base(new double[] { records[0], records[1] })
{
if (records.Count() != NumberOfFields)
throw new ArgumentException();
this.Field3 = records[2];
}
public override double this[int index]
{
get { throw new NotImplementedException(); }
}
}
public static class TestRecord
{
public static void CreateRecord()
{
var record = new ChildRecord(new double[]{1.0,1.5,2.5}); // Not working
}
}
This example crashes because of polymorphic call NumberOfFields
from ChildRecord
inside constructor of Record
.
As far as I know, I can use new
insted of override
to solve this problem, but in that case I cannot declare NumberOfFields
as abstract
in base class (which I needed).
What is the proper way to solve this problem? Is something wrong with the design?
The way you've formulated this, it cannot possibly work as intended. Assume it did (through some sort of some magic) work the way you think it should, and you were able to create your ChildRecord
:
var record = new ChildRecord(new double[] { 1.0, 1.5, 2.5 });
What would you expect the value of record.NumberOfFields
to be? Two or three? This particular object cannot be a ChildRecord
with NumberOfFields == 3
and at the same time be a Record
with NumberOfFields == 2
. You get the result of the NumberOfFields
implementation of the instantiated class, regardless of whether you type record
as ARecord
, Record
or ChildRecord
.
To put it another way: It makes no sense to expose ARecord.NumberOfFields
to the outside, as there is no one correct answer -- it isn't a meaningful concept.
If you abstain from exposing it, you can do your validation something like this (with indexers and properties omitted):
public abstract class ARecord
{
public abstract double this[int index] { get; }
}
public class Record : ARecord
{
private const int NumberOfFields = 2;
public Record(double[] records)
{
if (records.Count() != NumberOfFields)
throw new ArgumentException();
this.Field1 = records[0];
this.Field2 = records[1];
}
}
public class ChildRecord : Record
{
private const int NumberOfFields = 3;
public ChildRecord(double[] records)
: base(new double[] { records[0], records[1] })
{
if (records.Count() != NumberOfFields)
throw new ArgumentException();
this.Field3 = records[2];
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.