249

これはおそらく非常に単純な質問であることを私は知っていますが、私はしばらくの間その概念に苦労してきました。

私の質問は、C#でコンストラクターをどのようにチェーンするかです。

私は最初のOOPクラスにいるので、ただ学んでいます。コンストラクターの連鎖がどのように機能するのか、それを実装する方法、さらには連鎖せずにコンストラクターを実行するよりも優れている理由さえわかりません。

説明付きの例をいくつかいただければ幸いです。

では、どのようにそれらを連鎖させるのでしょうか?
私はそれが行くことを2つ知っています:

public SomeClass this: {0}

public SomeClass
{
    someVariable = 0
} 

しかし、3、4などでどのようにそれを行いますか?

繰り返しになりますが、これが初心者の質問であることは知っていますが、これを理解するのに苦労していて、理由がわかりません。

4

9 に答える 9

387

クラスで、標準の構文(thisメソッドのように使用)を使用してオーバーロードを選択します。

class Foo 
{
    private int id;
    private string name;

    public Foo() : this(0, "") 
    {
    }

    public Foo(int id, string name) 
    {
        this.id = id;
        this.name = name;
    }

    public Foo(int id) : this(id, "") 
    {
    }

    public Foo(string name) : this(0, name) 
    {
    }
}

それから:

Foo a = new Foo(), b = new Foo(456,"def"), c = new Foo(123), d = new Foo("abc");

注:

  • を使用して、基本型のコンストラクターにチェーンできますbase(...)
  • 各コンストラクターに追加のコードを入れることができます
  • デフォルト(何も指定しない場合)はbase()

「なぜ?」の場合:

  • コードの削減(常に良いこと)
  • デフォルト以外のベースコンストラクターを呼び出すために必要です。次に例を示します。

    SomeBaseType(int id) : base(id) {...}
    

ただし、同様の方法でオブジェクト初期化子を使用することもできます(何も記述しなくてもかまいません)。

SomeType x = new SomeType(), y = new SomeType { Key = "abc" },
         z = new SomeType { DoB = DateTime.Today };
于 2009-11-29T08:06:27.697 に答える
61

これを探している人に有効なポイントを提示したいだけです。4.0(VS2010)より前のバージョンの.NETを使用する場合は、上記のようにコンストラクターチェーンを作成する必要があることに注意してください。

ただし、4.0にとどまっている場合は、朗報です。これで、オプションの引数を持つ単一のコンストラクターを持つことができます!Fooクラスの例を簡略化します。

class Foo {
  private int id;
  private string name;

  public Foo(int id = 0, string name = "") {
    this.id = id;
    this.name = name;
  }
}

class Main() {
  // Foo Int:
  Foo myFooOne = new Foo(12);
  // Foo String:
  Foo myFooTwo = new Foo(name:"Timothy");
  // Foo Both:
  Foo myFooThree = new Foo(13, name:"Monkey");
}

コンストラクターを実装する場合、デフォルトが設定されているため、オプションの引数を使用できます。

このレッスンを楽しんでいただけたでしょうか。2004/2005年以降、開発者がコンストラクトチェーンについて不満を言っていて、デフォルトのオプションの引数を使用できないとは信じられません。現在、開発の世界では非常に長い時間がかかっているため、下位互換性がないため、開発者はそれを使用することを恐れています。

于 2011-01-13T14:36:39.313 に答える
31

これは例で最もよく説明されています。イメージング私たちはクラスの人を持っています

public Person(string name) : this(name, string.Empty)
{
}

public Person(string name, string address) : this(name, address, string.Empty)
{
}

public Person(string name, string address, string postcode)
{
    this.Name = name;
    this.Address = address;
    this.Postcode = postcode;
}

したがって、ここにいくつかのプロパティを設定するコンストラクターがあり、コンストラクターチェーンを使用して、名前だけ、または名前とアドレスだけでオブジェクトを作成できるようにします。名前だけでインスタンスを作成すると、デフォルト値string.Empty throughが名前とアドレスに送信され、Postcodeのデフォルト値が最終コンストラクターに送信されます。

そうすることで、作成したコードの量を減らすことができます。実際にコードが含まれているコンストラクターは1つだけで、繰り返しはありません。たとえば、Nameをプロパティから内部フィールドに変更する場合、1つのコンストラクターを変更するだけで済みます。3つのコンストラクターすべてにそのプロパティを設定する場合です。それを変更するには3つの場所になります。

于 2009-11-29T08:09:30.340 に答える
15

「コンストラクターチェーン」の使い方は?
別のコンストラクターから1つのコンストラクターを呼び出すために使用します。

「コンストラクタチェーン」はどのように実装できますか?
コンストラクターの定義の後に「:this(yourProperties)」キーワードを使用します。例えば:

Class MyBillClass
{
    private DateTime requestDate;
    private int requestCount;

    public MyBillClass()
    {
        /// ===== we naming "a" constructor ===== ///
        requestDate = DateTime.Now;
    }
    public MyBillClass(int inputCount) : this()
    {
        /// ===== we naming "b" constructor ===== ///
        /// ===== This method is "Chained Method" ===== ///
        this.requestCount= inputCount;
    }
}

なぜそれが役立つのですか?
重要な理由は、コーディングを減らし、重複コードを防ぐことです。プロパティを初期化するための繰り返しコードなどクラス内の一部のプロパティを特定の値(このサンプルではrequestDate)で初期化する必要があるとします。また、クラスには2つ以上のコンストラクターがあります。「コンストラクタチェーン」がない場合は、クラスのすべてのコンストラクタで初期化コードを繰り返す必要があります。

それがどのように働きますか?(または、「コンストラクタチェーン」の実行シーケンスとは)?
上記の例では、メソッド「a」が最初に実行され、次に命令シーケンスがメソッド「b」に戻ります。言い換えれば、上記のコードは以下と同じです。

Class MyBillClass
{
    private DateTime requestDate;
    private int requestCount;

    public MyBillClass()
    {
        /// ===== we naming "a" constructor ===== ///
        requestDate = DateTime.Now;
    }
    public MyBillClass(int inputCount) : this()
    {
        /// ===== we naming "b" constructor ===== ///
        // ===== This method is "Chained Method" ===== ///

        /// *** --- > Compiler execute "MyBillClass()" first, And then continue instruction sequence from here
        this.requestCount= inputCount;
    }
}
于 2016-12-13T06:34:05.773 に答える
12

私は日記のクラスを持っているので、何度も値を設定することを書いていません

public Diary() {
    this.Like = defaultLike;
    this.Dislike = defaultDislike;
}

public Diary(string title, string diary): this()
{
    this.Title = title;
    this.DiaryText = diary;
}

public Diary(string title, string diary, string category): this(title, diary) {
    this.Category = category;
}

public Diary(int id, string title, string diary, string category)
    : this(title, diary, category)
{
    this.DiaryID = id;
}
于 2012-07-18T16:13:31.180 に答える
6

あなたはこれについて尋ねていますか?

  public class VariantDate {
    public int day;
    public int month;
    public int year;

    public VariantDate(int day) : this(day, 1) {}

    public VariantDate(int day, int month) : this(day, month,1900){}

    public VariantDate(int day, int month, int year){
    this.day=day;
    this.month=month;
    this.year=year;
    }

}
于 2009-11-29T08:07:39.050 に答える
4

これらの答えはすべて良いですが、もう少し複雑な初期化を行うコンストラクターについてのメモを追加したいと思います。

class SomeClass {
    private int StringLength;
    SomeClass(string x) {
         // this is the logic that shall be executed for all constructors.
         // you dont want to duplicate it.
         StringLength = x.Length;
    }
    SomeClass(int a, int b): this(TransformToString(a, b)) {
    }
    private static string TransformToString(int a, int b) {
         var c = a + b;
         return $"{a} + {b} = {c}";
    }
}

この例は、この静的関数がなくても解決できる可能性がありますが、静的関数を使用すると、より複雑なロジックを使用したり、別の場所からメソッドを呼び出したりすることもできます。

于 2020-11-24T14:22:00.097 に答える
2

次の例がコンストラクターの連鎖に光を当てることを願っています。
たとえば、ここでの私の使用例では、ユーザーがコンストラクターにディレクトリを渡すことを期待しています。ユーザーは渡すディレクトリがわからず、デフォルトのディレクトリを割り当てることにしました。ステップアップして、機能すると思われるデフォルトのディレクトリを割り当てます。

ところで、*。Dump()が何であるか疑問に思っている場合に備えて、この例ではLINQPadを使用しました。
乾杯

void Main()
{

    CtorChaining ctorNoparam = new CtorChaining();
    ctorNoparam.Dump();
    //Result --> BaseDir C:\Program Files (x86)\Default\ 

    CtorChaining ctorOneparam = new CtorChaining("c:\\customDir");
    ctorOneparam.Dump();    
    //Result --> BaseDir c:\customDir 
}

public class CtorChaining
{
    public string BaseDir;
    public static string DefaultDir = @"C:\Program Files (x86)\Default\";


    public CtorChaining(): this(null) {}

    public CtorChaining(string baseDir): this(baseDir, DefaultDir){}

    public CtorChaining(string baseDir, string defaultDir)
    {
        //if baseDir == null, this.BaseDir = @"C:\Program Files (x86)\Default\"
        this.BaseDir = baseDir ?? defaultDir;
    }
}
于 2013-04-11T00:08:04.050 に答える
2

コンストラクターチェーンにはもう1つの重要なポイントがあります。それは順序です。なんで?デフォルトのコンストラクターを期待するフレームワークによって実行時にオブジェクトが構築されているとしましょう。必要なときにコンストラクター引数を渡す機能を持ちながら値を渡すことができるようにしたい場合、これは非常に便利です。

たとえば、デフォルトのコンストラクターによってデフォルト値に設定されるが、上書きする機能を持つバッキング変数を作成できます。

public class MyClass
{
  private IDependency _myDependency;
  MyClass(){ _myDependency = new DefaultDependency(); }
  MYClass(IMyDependency dependency) : this() {
    _myDependency = dependency; //now our dependency object replaces the defaultDependency
  }
}
于 2015-12-18T12:31:04.977 に答える