web-dev-qa-db-ja.com

C#でのオーバーライドされたコンストラクターとベースコンストラクターの呼び出し

次のようなコンストラクターを持つ2つのクラスFooとBarがあります。

class Foo
{
    Foo()
    {
      // do some stuff
    }

    Foo(int arg)
    {
      // do some other stuff
    }
}

class Bar : Foo
{
    Bar() : base()
    {
      // some third thing
    }
}

ここで、intを取るBarのコンストラクターを紹介しますが、Bar()で発生するものをFoo(int)からのものとして同様にを実行する必要があります。このようなもの:

Bar(int arg) : Bar(), base(arg)
{
  // some fourth thing
}

これをC#で行う方法はありますか?これまでのところ、Bar()によって行われた作業を関数に入れ、それもBar(int)によって呼び出されますが、これはかなり洗練されていません。

50
reilly

いいえ、できません。 Reflectorを使用して、各コンストラクターに対して生成されたILを調べると、理由がわかります。つまり、基本クラスの両方のコンストラクターを呼び出すことになります。理論的には、コンパイラーは隠されたメソッドを作成して目的を達成することができますが、同じことを明示的に行うことに勝る利点はありません。

24

私はコンストラクタを再チェーンするので、それらは次のように呼び出されます

Bar() : this(0) 
Bar(int) : Foo(int) initializes Bar
Foo(int) initializes Foo
Foo() : this(0) 

これは、パラメーターなしのコンストラクターが他のコンストラクターのintパラメーターのある種のデフォルト値を想定している場合に適しています。コンストラクターが無関係である場合、おそらく型で何か間違っているか、またはおそらく何を達成しようとしているのかについての詳細情報が必要です。

32
Ilya Ryzhenkov

コンストラクタチェーンを変更して、最も具体的でないものから最も具体的なものに変更することをお勧めします。

class Foo
{
    Foo()
    {
      // do some stuff
    }

    Foo(int arg): this()
    {
      // do some other stuff
    }
}

class Bar : Foo
{
    Bar() : Bar(0)
    {
      // some third thing
    }

    Bar(int arg): base(arg)
    {
      // something
    }
}

Barオブジェクトを作成すると、4つのコンストラクタすべてが呼び出されます。コンストラクターチェーニングは、より具体的なコンストラクターにデフォルト値を提供する必要があり、その逆ではありません。あなたは本当に自分が達成しようとしていることを見て、あなたがしていることが理にかなっていることを確かめるべきです。 Curtは、これを実行できない技術的な理由があることは正しいですが、実行できない論理的な理由もあります。

13
NerdFury

これは私が考えることができる唯一のものです...

 public class Foo
{
    public Foo()
    {
    }
    public Foo(int? arg): this()
    {
    }

}
public class Bar : Foo
{
    private int x;
    public Bar(): this(new int?()) // edited to fix type ambiguity
    {
        // stuff that only runs for paramerless ctor
    }
    public Bar(int? arg)
        : base(arg)
    {
        if (arg.HasValue)
        {
            // Do stuff for both parameterless and parameterized ctor
        }
        // Do other stuff for only parameterized ctor
    }
}
4
Charles Bretana

Intを引数なしのコンストラクターで呼び出すBarコンストラクターはありませんか?

1
Jim Anderson

Bar()からのものをBar(int)に入れて、デフォルト値でBar()を使用してBar(int)を呼び出すことはできますか?次に、Bar(int)は基本コンストラクターを呼び出すことができます。

class Bar : Foo
{
    Bar() : this(0)
    {
    }

    Bar(int arg) : base(arg)
    {
    }
}

それはあなたの質問に正確に答えるものではありませんが、シナリオによっては実行可能な解決策になるかもしれません。

1
g .

bar()の初期化コードを取得し、それをメソッドにして両方のコンストラクターから呼び出し、新しいコンストラクターにbase(arg)を呼び出させるだけですか?

1
CSharpAtl

次のコードを使用できます。

_public Foo
{
    public Foo()
    {
        this.InitializeObject();
    }

    public Foo(int arg) : this()
    {
        // do something with Foo's arg
    }

    protected virtual void InitializeObject()
    {
        // initialize object Foo
    }
}

public Bar : Foo
{
    public Bar : base() { }

    public Bar(int arg) : base(arg)
    {
       // do something with Bar's arg
    }

    protected override void InitializeObject()
    {
       // initialize object Bar

       base.InitializeObject();
    }
}
_

上記のコードのようにInitializeObject()メソッドをオーバーライドし、パラメーターなしのコンストラクターに配置するすべてのコードをそこに配置します。そして最後に、コードの最後でbase.InitializeObject()を呼び出します。

これがお役に立てば幸いです。

0
Moch Yusup