1

以下の 2 つのクラスを考えると、int パラメーターを使用して Child コンストラクターを呼び出し、次に int パラメーターを使用して親コンストラクターを呼び出し、最後に Child パラメーターなしのコンストラクターを呼び出したいと思います。

これは、オプションのパラメーターを使用せずに実行できますか?

public class Parent
{
    public Parent()
    {
        Console.WriteLine("Parent ctor()");
    }

    public Parent(int i)
    {
        Console.WriteLine("Parent ctor(int)");
    }
}

public class Child:Parent
{
    public Child()
    {
        Console.WriteLine("Child ctor()");
    }

    public Child(int i)
    {
        Console.WriteLine("Child ctor(int)");
    }
}

.NET 2.0 で達成したい .NET 4 のロジックは次のとおりです。

public class Parent2
{
    public Parent2(int? i = null)
    {
        Console.WriteLine("Parent2 ctor()");

        if (i != null)
        {
            Console.WriteLine("Parent2 ctor(int)");

        }
    }
}

public class Child2 : Parent2
{
    public Child2(int? i = null)
        : base(i)
    {
        Console.WriteLine("Child2 ctor()");

        if (i != null)
        {
            Console.WriteLine("Child2 ctor(int)");
        }
    }
}

これが、私たちが議論していた製品コードです

public class DataPoint<T>
{
    public DataPoint() { }

    public DataPoint(T xValue, int yValue)
    {
        XAxis = xValue;
        YAxis = yValue;
    }

    public T XAxis { get; set; }
    public int YAxis { get; set; }
}

public class DataPointCollection<T> : DataPoint<T>
{
    DataPointCollection()
    {
        Labels = new List<string>();
    }

    DataPointCollection(T xValue, int yValue)
        : base(xValue, yValue)
    { }

    public List<string> Labels { get; set; }
}

編集:

この時点での質問の理由は、最小量のコードで DRY 方法論に従うための「コード ゴルフ」アカデミック エクササイズです。通常のパターンは、各コンストラクターから実行する共通コードを持つクラスで内部プライベート関数を使用することです。

編集2

実動コードの例を追加しました。

4

5 に答える 5

2

Childいいえ、それはできません。コンストラクターを から呼び出すことができないためですParent

于 2012-07-27T18:15:01.080 に答える
1

一連の初期化メソッドが必要な場合は、通常の(コンストラクターではない)メソッドとして定義することをお勧めします。コンストラクターは任意の組み合わせまたは順序で呼び出す初期化メソッドを選択できるため、オーバーライド可能な保護されたメソッドを使用して前後にセットアップできます。

public class Parent {

    public Parent() { }

    public Parent(int i) {
        initWithArg(i);
        initNoArgs();
    }

    virtual protected void initWithArg(int i) {
        Console.WriteLine("Parent initWithArg(int)");
    }

    virtual protected void initNoArgs() {
        Console.WriteLine("Parent initNoArgs");
    }
}

public class Child : Parent {

    // Override the *parameterless* constructor
    public Child(int i) : base() {
        initWithArg(i);
        base.initWithArg(i);
        initNoArgs();
    }

    override protected void initWithArg(int i) {
        Console.WriteLine("Child initWithArg(int)");
    }

    override protected void initNoArgs() {
        Console.WriteLine("Child initNoArgs");
    }
}
于 2012-07-27T18:28:35.647 に答える
0

いくつかの選択肢がありますが、どれも完璧ではありません。最後に、私の主な推奨事項は、(明らかに) 可能であれば .NET 4.0 にアップグレードすることです。

これが1つのオプションです。オブジェクトを使用して、そこに必要なものとしてキャストします。タイピングを失ったり署名を壊したりするので、これは明らかな欠点ですが、あなたの状況ではうまくいくかもしれません。

public class Parent3
{
    public Parent3(object i)
    {
        Console.WriteLine("Parent3 ctor()");

        if (i != null)
        {
            Console.WriteLine("Parent3 ctor(int)");
        }
    }
}

public class Child3 : Parent3
{
    public Child3(object i)
        : base(i)
    {
        Console.WriteLine("Child3 ctor()");

        if (i != null)
        {
            Console.WriteLine("Child3 ctor(int)");
        }
    }
}

Init メソッドを使用する別のオプションがあります。ただし、まったく同じ順序で起動するわけではありませんが、うまくいく可能性があります。

    public class Parent
{
    public Parent()
    {
        Init();
    }

    protected void Init()
    {
        Console.WriteLine("Parent ctor()");
    }

    public Parent(int i)
    {
        Init(i);
    }

    protected void Init(int i)
    {
        Console.WriteLine("Parent ctor(int)");
    }
}

public class Child : Parent
{
    public Child()
    {
        Init();
    }

    protected void Init()
    {
        Console.WriteLine("Child ctor()");
    }

    public Child(int i)
    {
        Init(i);
        base.Init(i);
        Init();
    }


    protected void Init(int i)
    {
        Console.WriteLine("Child ctor(int)");
    }

}

次に、私が本当にお勧めしない方法を次に示しますが、とにかくそれを含めます

    public class Parent
{
    public Parent()
    {
        Console.WriteLine("Parent ctor()");
    }

    public Parent(int i)
    {
        Console.WriteLine("Parent ctor(int)");
    }
}

public class Child : Parent
{
    private static int _i; //this is likely to blow up at some point.

    public Child() : base(_i)
    {
        Console.WriteLine("Child ctor()");
    }

    public Child(int i) : this()
    {
        _i = i;
        Console.WriteLine("Child ctor(int)");
    }
}
于 2012-07-27T18:40:33.000 に答える
0

Child(int i)次のようにコンストラクターを定義することで、質問の最初の部分を達成できます。

public Child(int i) : base(i)
{
    Console.WriteLine("Child ctor(int)");
}

Childただし、前述のように、後で別の のコンストラクターを呼び出すことはできません。実際の目標 (これは純粋に学術的な質問ではないと仮定します) が、 のデフォルト コンストラクターに含まれる標準的な動作を常に実行することである場合は、それをメソッドにカプセル化し、各のコンストラクターChildから呼び出す方がよい場合があります。Child

public class Child:Parent
{
    public Child()
    {
        Console.WriteLine("Child ctor()");
        CommonChildConstructionBehaviour();
    }

    public Child(int i) : base(i)
    {
        Console.WriteLine("Child ctor(int)");
        CommonChildConstructionBehaviour();
    }

    private void CommonChildConstructionBehaviour()
    {
        Console.WriteLine("All child constructors must call me.");
    }
}
于 2012-07-27T18:19:43.133 に答える
0

継承は一方向としてのみ機能します。

Child--->Parent

飼いならされたときに同じクラスの2つのコンストラクターを呼び出さなければならないシナリオがないため、おそらく構造エラーがあります(私が間違っている場合は誰かが私を修正してください) 。

それ自体を呼び出すため、再帰コンストラクターを除いて、同じことではありません。

于 2012-07-27T18:15:35.980 に答える