6

C#でコンストラクターをチェーンするときに実行順序を変更する方法を知りたいです。私が見た唯一のメソッドでは、現在のコンストラクターの外部で、チェーンコンストラクターを最初に呼び出す必要があります。

具体的には、次の例を見てください。

public class Foo {
  private static Dictionary<string, Thing> ThingCache = new Dictionary<string, Thing>();
  private Thing myThing;

  public Foo(string name) {
    doSomeStuff();
    if (ThingCache.ContainsKey(name)) {
      myThing = ThingCache[name];
    } else {
      myThing = ExternalStaticFactory.GetThing(name);
      ThingCache.Add(name, myThing);
    }
    doSomeOtherStuff();
  }

  public Foo(Thing tmpThing) {
    doSomeStuff();
    myThing = tmpThing;
    doSomeOtherStuff();
  }
}

理想的には、これを行うことでコードの繰り返しを減らしたいと思います(この不自然な例では、あまり多くのコードが保存されていないことを認めますが、はるかに有益なコードで作業しています。わかりやすくするためにこの例を使用します):

public class Foo {
  private static Dictionary<string, Thing> ThingCache = new Dictionary<string, Thing>();
  private Thing myThing;

  public Foo(string name) {
    if (ThingCache.ContainsKey(name)) {
      this(ThingCache[name]);
    } else {
      this(ExternalStaticFactory.GetThing(name));
      ThingCache.Add(name, myThing);
    }
  }

  public Foo(Thing tmpThing) {
    doSomeStuff();
    myThing = tmpThing;
    doSomeOtherStuff();
  }
}

これはVB.Netで可能ですが、C#では、別のコンストラクターの途中でコンストラクターを呼び出すことはできません。最初にFoo():this()構文を使用する場合のみです。

だから私の質問は、最初に他のコンストラクターを呼び出すことしかできないコロン構文を使用するのではなく、コンストラクターをチェーンするときにコンストラクターを呼び出す順序をどのように制御するのですか?

4

4 に答える 4

8

他のコンストラクター内でコンストラクターを呼び出すことはできません。コンストラクターは、その直前に呼び出される別のコンストラクターのみをチェーンできます。

ただし、特定の問題を解決するために、両方のタイプの引数を受け入れることができるプライベートコンストラクターを作成し、2つの元のコンストラクターの両方に、この1つをチェーンして、欠落している引数にnullを渡すことができます。

これには、プライベート初期化メソッドを呼び出すよりも、フィールドでうまく機能するという利点があります(つまり、がフィールドのreadonly場合でも機能します)。myThingreadonly

public class Foo
{
    private static Dictionary<string, Thing> ThingCache =
        new Dictionary<string, Thing>();
    private Thing myThing;

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

    public Foo(Thing tmpThing)
        : this(tmpThing, null)
    {
    }

    private Foo(Thing tmpThing, string name)
    {
        if (tmpThing == null && name == null)
        {
            throw new System.ArgumentException(
                "Either tmpThing or name must be non-null.");
        }

        doSomeStuff();
        if (tmpThing != null)
        {
            myThing = tmpThing;
        }
        else
        {
            if (ThingCache.ContainsKey(name))
            {
                myThing = ThingCache[name];
            }
            else
            {
                myThing = ExternalStaticFactory.GetThing(name);
                ThingCache.Add(name, myThing);
            }
        }
        doSomeOtherStuff();
    }
}

C#4.0を使用している場合は、名前付き引数またはオプションの引数を使用することもできます。

http://msdn.microsoft.com/en-us/library/dd264739.aspx

于 2011-03-24T23:34:39.933 に答える
7

C#でコンストラクターをチェーンするときに実行順序を変更する方法を知りたいです。

あなたはそうしない。C#にはそのような機能はありません。

任意のコードを任意の順序で呼び出すメカニズムはすでに存在します。一連のメソッドを作成し、それらを好きな順序で呼び出します。

これが、このテーマに関する私の記事です。

http://blogs.msdn.com/b/ericlippert/archive/2010/01/28/calling-constructors-in-arbitrary-places.aspx

コンストラクターチェーンの設計原則のトピックに関心がある場合は、以下もお読みください。

http://blogs.msdn.com/b/ericlippert/archive/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx

于 2011-03-24T23:25:15.443 に答える
1

クラス内にプライベート初期化メソッドを作成し、コンストラクターロジックにそれらのメソッドを呼び出させます。

class Foo
{
 public Foo(string name) 
 {
   InitializeBefore();

   if (ThingCache.ContainsKey(name)) 
   {
      myThing = ThingCache[name];
   } else 
   {
     myThing = ExternalStaticFactory.GetThing(name);
     ThingCache.Add(name, myThing);
   }

   InitializeAfter();
 }

 public Foo(Thing tmpThing) 
 {
   InitializeBefore();
   myThing = tmpThing;
   InitializeAfter();
 }

 private void InitializeBefore() 
 {
   doSomeStuff();
   // and any other calls you want before 
 }

 private void InitializeAfter() 
 {
   doSomeOtherStuff();
   // and any other calls you want at the end of the constructor
 }

}
于 2011-03-24T23:17:39.843 に答える
0

メソッドを使用する必要があります。最も簡単な翻訳は次のとおりです。

public class Foo {
  private static Dictionary<string, Thing> ThingCache = new Dictionary<string, Thing>();
  private Thing myThing;

  public Foo(string name) {
    if (ThingCache.ContainsKey(name)) {
      Init(ThingCache[name]);
    } else {
      Init(ExternalStaticFactory.GetThing(name));
      ThingCache.Add(name, myThing);
    }
  }

  public Foo(Thing tmpThing) {
    Init(tmpThing);
  }

  private void Init(Thing tmpThing) {
    doSomeStuff();
    myThing = tmpThing;
    doSomeOtherStuff();
  }
}

少なくとも読み取り専用フィールドがない限り。他のコンストラクターを任意の場所で呼び出す構文には、その利点があることを認めなければなりません。

于 2011-03-24T23:35:56.983 に答える