C#中的多个参数用于DRY输出参数传递

时间:2010-01-11 21:08:24

标签: c# parameters arguments syntactic-sugar

我不知道这是否可行,但在我的一些单元测试中,我最终用相同的参数初始化不同的对象。我希望能够将这些参数存储在某个变量中,并使用该变量初始化多参数对象构造函数,而不是执行:

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

7 个答案:

答案 0 :(得分: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 :(得分: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。你可以做些什么来修复它实际上在参数中接受一个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实例,每个实例都有自己的属性对象。

答案 2 :(得分:1)

还有这个,假设你的Thing1是一个琐碎的对象,你只需要一个浅的副本:

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

答案 3 :(得分: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]);
        }
    }

答案 4 :(得分:1)

我建议调查Test Data Builder模式。当您有许多参数可以独立变化,重复使用等时,它的效果非常好。

您可以使用properties + object initializers for 'flat' classes或流体方法链接作为替代方法。我玩弄了两者,各有其优势。

优点:

  • 您可以捕获变量/值 用于构造对象的
  • 如果是,您可以重复使用构建器实例 它所采用的值是简单类型 和/或不可变的(值类型, 字符串等)
  • 您可以改变每个人 参数独立无噪音 / code duplication它进行测试 读得非常好,而不是 必须记住哪个ctor param 是哪个,你看到了这个名字。

如果您需要创建每个参数的新实例,请查看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();

答案 5 :(得分: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)

答案 6 :(得分:0)

如果你需要多次这样做,你也可以使用一个对象数组和一个for循环。