web-dev-qa-db-ja.com

base()およびthis()コンストラクターのベストプラクティス

どのような条件下で、コンストラクターの括弧に続いて(またはコード内の他の場所でも):base()および:this()コンストラクターを呼び出すことになっています。これらはいつ良い習慣と呼ばれ、いつ義務付けられますか?

77
explorer

: base(...)

基本コンストラクターの呼び出しを省略すると、デフォルトの基本コンストラクターが自動的に呼び出されます。

デフォルトのコンストラクターがない場合は、明示的に基本コンストラクターを呼び出す必要があります。

デフォルトのコンストラクターがある場合でも、デフォルトのコンストラクターとは異なるコンストラクターを呼び出すことができます。この場合、base(foo, bar)を使用して、基本コンストラクターとは異なるコンストラクターを呼び出すこともできます。

基本クラスのデフォルトコンストラクターを呼び出したいときにbase()を省略するのは悪い習慣ではないと思いますが、明示的にしたい場合は害を加えません。それは好みの問題です。

: this(...)

この構文を使用すると、同じクラス内の別のシグネチャとは異なるシグネチャを持つ1つのコンストラクターを呼び出すことができます。これは必須ではありませんが、役に立つ場合があります。

便利な場合の例は、コンストラクターで一般的なコードを再利用する場合です。たとえば、C#3.5以前では、コンストラクターでオプションのパラメーターをシミュレートできます。

Foo(int x, int y)
{
     this.x = x;
     this.y = y;
}

Foo(int x) : this(x, 10) {}  // y defaults to 10

C#4.0では、オプションのパラメーターが利用可能になり、このアプローチの必要性が減りました。

コンストラクターでコードを再利用する別の方法は、使用したい各コンストラクターから呼び出される静的関数にコードを分解することです。

98
Mark Byers

最初に、必須の場合。

クラスDerivedがクラスBaseから派生し、Baseにデフォルト(パラメーターなし)コンストラクターがない場合、Derivedbase()パラメータを明示的に使用します。

public class Base {
    public Base(int i) { }
}


public class Derived : Base {
    // public Derived() { } wouldn't work - what should be given for i?
    public Derived() : base(7) { }
    public Derived(int i) : base(i) { }
}

いつ良い習慣ですか?別のコンストラクターを呼び出したいときはいつでも。

前の例で、Derivedのコンストラクターにコンテンツを追加するとします。

public class Derived : Base {
    // public Derived() { } wouldn't work - what should be given for i?
    public Derived() : base(7) {
        Console.WriteLine("The value is " + 7);
    }
    public Derived(int i) : base(i) {
        Console.WriteLine("The value is " + i);
    }
}

ここで重複に気付きましたか? this()コンストラクターを呼び出す方が簡単です。

public class Derived : Base {
    // public Derived() { } wouldn't work - what should be given for i?
    public Derived() : this(7) { }
    public Derived(int i) : base(i) {
        Console.WriteLine("The value is " + i);
    }
}
34
configurator

継承があり、親クラスが既に達成しようとしている機能を提供している場合は、baseを使用します。

現在のエンティティ(またはself)を参照する場合はthisを使用し、別のコンストラクターで既に定義されている機能を複製したくない場合はコンストラクターのヘッダー/署名で使用します。

基本的に、baseを使用し、コンストラクターのヘッダーでこれを使用すると、コードを保持できます [〜#〜] dry [〜#〜]

これはまったく意味のない例ですが、この2つをどのように使用できるかを示すアイデアを示していると思います。

class Person
{
    public Person(string name)
    {
        Debug.WriteLine("My name is " + name);
    }
}

class Employee : Person
{
    public Employee(string name, string job)
        : base(name)
    {
        Debug.WriteLine("I " + job + " for money.");
    }

    public Employee() : this("Jeff", "write code")
    {
        Debug.WriteLine("I like cake.");
    }
}

使用法:

var foo = new Person("ANaimi");
// output:
//  My name is ANaimi

var bar = new Employee("ANaimi", "cook food");
// output:
//  My name is ANaimi
//  I cook food for money.

var baz = new Employee();
// output:
//  My name is Jeff
//  I write code for money.
//  I like cake.
30
ANaimi

「C#でのコンストラクターチェーン」を探します。基本的には次のようになります。

MyClass():base()  //default constructor calling superclass constructor
{
}

MyClass(int arg):this()  //non-basic constructor calling base constructor
{
    //extra initialization
}

コンストラクター内のコードの重複を削除するのに役立ちます-それらを基本部分と特定部分に分割します。

8
alxx

基本クラスのコンストラクターをコンストラクターの最初の命令として自動的に呼び出すには、:base()を使用します。 :this()は似ていますが、同じクラスの別のコンストラクターを呼び出します。

Base :()およびthis()では、定数値、またはコンストラクターのパラメーターに基づく式としてパラメーターとして渡すことができます。

基本クラスに既定のコンストラクター(パラメーターを受け取らないコンストラクター)がない場合、基本コンストラクターを呼び出すことは必須です。 :this()が必須のケースは知りません。

public class ABaseClass
{
    public ABaseClass(string s) {}
}

public class Foo : AChildClass
{
    public AChildClass(string s) : base(s) {} //base mandatory
    public AChildClass() : base("default value") {}  //base mandatory
    public AChildClass(string s,int i) : base(s+i) {}  //base mandatory
}

public class AnotherBaseClass
{
    public ABaseClass(string s) {}
    public ABaseClass():this("default value") {} //call constructor above
}

public class Foo : AnotherChildClass
{
    public AnotherChildClass(string s) : base(s) {} //base optional

}
4
Andrea Parodi