简体   繁体   中英

Call base class override method from base constructor C#

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM