8

これが可能かどうかはわかりませんが、一部の単体テストでは、同じ引数を使用して異なるオブジェクトを初期化することになります。これらの引数をいくつかの変数に格納し、マルチパラメーターオブジェクトコンストラクターをその変数で初期化できるようにしたいので、次のようにする代わりに、次のようにします。

Thing thing1 = new Thing(arg1, arg2, arg3, arg4);
Thing thing2 = new Thing(arg1, arg2, arg3, arg4);
Thing thing3 = new Thing(arg1, arg2, arg3, arg4);

私は次のことができます:

MagicalArgumentsContainer args = (arg1, arg2, arg3, arg4);
Thing thing1 = new Thing(args);
Thing thing2 = new Thing(args);
Thing thing3 = new Thing(args);

Thingのコンストラクターをオーバーライドして、手動で展開して引数を抽出するリストを取得せずにこれを行う方法はありますか?多分いくつかのC#シンタックスシュガー?

4

7 に答える 7

13

つまり、これがあります:

Func<Thing> f = () => new Thing(arg1, arg2, arg3, arg4);
Thing thing1 = f();
Thing thing2 = f();
Thing thing3 = f();
Thing thing4 = f();

クロージャのセマンティクスに注意してください。

于 2010-01-11T21:10:53.747 に答える
3

IoC コンテナーを使用できると思います。これのいくつかは ObjectFactory も提供するためです。つまり、IoC に T 型の新しいインスタンスを作成する方法を伝えてから、IoC にそのインスタンスを提供するように依頼するだけです。

ただし、IoCを取得したくない場合は、自分自身を小さなファクトリークラスにすることができます

public MagicFactory
{
   T arg1, T2 arg2,  T3 arg3,.., TN argN;

   public MagicFactory(T1 a1,..., TN aN)
   {
      this.arg1=a1;
       ...
      this.argN = an;
   }

   public Thing GimmeDaThing()
   {
      return new Thing(this.arg1,...,this.argN);
   }
}

ただし、引数が値型でない場合、のすべてのインスタンスはThing同じオブジェクトへの参照を持つことになるため、Thing のインスタンスが異なっていても、それらはすべて同じ arg1 を指すことに注意してください。これを修正するためにできることは、実際にパラメーターに Func を取り込むことです。これにより、実際に新しいものを作成できます。

public MagicFactory
{
   Func<T1> arg1, ,.., Func<TN> argN;

   public MagicFactory(Func<T1> a1,..., Func<TN> aN)
   {
      this.arg1=a1;
       ...
      this.argN = an;
   }

   public Thing GimmeDaThing()
   {
      return new Thing(this.arg1(),...,this.argN());
   }
}

次のように呼び出します。

var magicContainer = new MagicFactory(()=> new T1(...),..., ()=>new T2(..);


var thing1 = magicContainer.GimmeDaThing();
var thing1 = magicContainer.GimmeDaThing();
var thing1 = magicContainer.GimmeDaThing();
var thing1 = magicContainer.GimmeDaThing();

そして、それぞれ独自のプロパティ オブジェクトを持つ Thing の新しいインスタンスを毎回取得します。

于 2010-01-11T21:52:35.280 に答える
1

params次のように、メソッドで宣言を使用します。

public Thing(params string[] args)
{
    foreach(string s in args)
    {
        ...
    }
}

そしてそれはあなたが以下をすることを可能にするでしょう:

result = Things(arg1)
result = Things(arg1,arg2)
result = Things(arg1,arg2,arg3)
result = Things(arg1,arg2,arg3,arg4)
于 2011-03-26T08:13:46.387 に答える
1

Thing1 が自明なオブジェクトであり、浅いコピーが必要であると仮定すると、これもあります。

Thing thing1 = new Thing(arg1, arg2, arg3, arg4);
Thing thing2 = (Thing)thing1.MemberwiseClone();
于 2010-01-11T21:13:34.257 に答える
1

少しジェネリックを使用するGimmieAThing ようなものに書き直すことができますか?GimmieAThing<T>

public class MagicalArgumentsContainer
    {
            object[] _myParams;

            public MagicalArgumentsContainer (params object[] myParams)
            {
            _myParams = myParams;
            }

            public Thing GimmieAThing()
            {
    return new Thing(_myParams[0], _myParams[1], _myParams[2], _myParams[3]);
        }
    }
于 2010-01-11T21:22:09.620 に答える
1

Test Data Builderパターンを調べることをお勧めします。個別に変更したり、再利用したりしたい多くのパラメータがある場合に、非常にうまく機能します。

代わりに、 「フラット」クラスのプロパティ + オブジェクト初期化子、または流動的なメソッド チェーンを使用できます。私は両方をいじりましたが、それぞれに利点があります。

利点:

  • オブジェクトの構築に使用された変数/値をキャプチャできます
  • 値が単純な型および/または不変 (値の型、文字列など) である場合は、ビルダー インスタンスを再利用できます。
  • ノイズやコードの重複なしに、各 ctor パラメーターを個別に変更できます。どの ctor パラメーターがどれであるかを覚えておく必要がなく、名前が表示されるため、テストが非常に読みやすくなります。

各パラメーターの新しいインスタンスを作成する必要がある場合は、bangoker の回答を確認してください。

とにかく、ここにいくつかのコードがあります:

public class ThingBuilder
{
   // set up defaults so that we don't need to set them unless required
   private string m_bongoName = "some name";
   private DateTime m_dateTime = new DateTime(2001, 1, 1);
   private int m_anotherArg = 5;
   private bool m_isThisIsGettingTedious = true;

   public ThingBuilder BongoName(string bongoName)
   {
      m_bongoName = bongoName;
      return this;
   }

   public ThingBuilder DateTime(DateTime dateTime)
   {
      m_dateTime = dateTime;
      return this;     
   }

   // etc. for properties 3...N

   public Thing Build()
   {    
      return new Thing(m_bongoName, m_dateTime, m_anotherArg, m_isThisGettingTedious);
   }
}

使用法 (1 回のインスタンス):

// notice that the parameters are now explicitly named + readable!
Thingy builtInstance = new ThingBuilder()
                           .BongoName("um bongo")
                           .DateTime(DateTime.Now)
                           .GettingTedious(true)
                           .Build();

複数のインスタンス:

var builder = new ThingBuilder()
                  .BongoName("um bongo")
                  .DateTime(DateTime.Now)
                  .GettingTedious(true);

// let's make multiple objects
Thing builtThing = builder.Build();
Thing anotherBuiltThing = builder.Build();
于 2010-01-11T22:36:15.287 に答える
0

これを何度も行う必要がある場合は、オブジェクトの配列と for ループを使用することもできます。

于 2010-01-11T21:18:11.920 に答える