2010-01-11 97 views
8

我不知道這是否可能,但在我的一些單元測試中,我最終使用相同的參數初始化不同的對象。我希望能夠將這些參數存儲在某個變量,只是初始化變量的多參數對象的構造等等,而不是做的:C#多個參數在一個乾燥出參數傳遞

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#語法糖?

+1

不,你想使用Ruby =)。 – 2010-01-11 21:16:10

+2

Python的論點拆包是一種幸福! – 2010-01-11 21:18:45

+1

我對自己想,如果我在這個項目上使用Ruby,我不會問這個問題。 – 2010-01-11 21:18:58

回答

13

我的意思是,有這樣的:

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

只是要小心的closure semantics

+1

是的,這就像一個InLine微小的ObjectFactory,但要考慮到,如果arg1-arg4是引用類型,那麼你所有的東西將共享這些對象,如果它們是值類型,或者你不在乎它們是否共享,那可能是最簡單的 – 2010-01-11 21:55:46

+0

在我的情況下,arg1-4是字符串,所以它都很好。 – 2010-01-12 15:00:23

1

還有這個,假設你Thing1是一個平凡的對象,你只需要一個淺拷貝:

Thing thing1 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing2 = (Thing)thing1.MemberwiseClone(); 
0

你也可以,如果你需要做這麼多使用對象的for循環數組和倍。

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]); 
     } 
    } 
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實例將有相同的對象的引用,所以,即使你有不同的事物的實例,他們都會指向相同的arg1。你可以做些什麼來解決這個問題是實際採取在參數函數求,所以實際上你可以創建一個新:

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實例,每個都有自己的屬性對象。

+1

public MagicFactory ? – gingerbreadboy 2010-01-11 23:19:48

1

我建議看看Test Data Builder模式。當你有很多參數需要獨立改變,重新使用等等時,它可以很好地工作。

您可以使用properties + object initializers for 'flat' classes或流體方法鏈作爲替代。我玩過兩種玩具,每種玩具都有其優點。

優點:

  • 您可以捕獲變量/值 了用來構造一個對象
  • 你可以,如果 需要的值是簡單類型重複使用建設者實例 和/或不可變(值類型, 字符串等)
  • 您可以獨立變化每個參數 無噪音 /代碼複製它使測試 閱讀真的很好,而不是 不得不記得哪個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); 
    } 
} 

使用(一次實例):

// 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(); 
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)