2010-01-11 56 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)