代码之家  ›  专栏  ›  技术社区  ›  Sarah Vessels

C一个参数中包含多个参数,以消除传递的参数

  •  8
  • Sarah Vessels  · 技术社区  · 15 年前

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

    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 回复  |  直到 13 年前
        1
  •  13
  •   jason    15 年前

    我是说,这里有:

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

    小心点 closure semantics .

        2
  •  3
  •   Francisco Noriega    15 年前

    好吧,我想你可以使用一个IOC容器,因为其中一些容器也提供了一个ObjectFactory,即你告诉IOC如何创建一个T类型的新实例,然后你只需要让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();
    

    你每次都会得到一个新的实例,每个都有自己的属性对象。

        3
  •  1
  •   womp    15 年前

    还有一个问题,假设你的Thing1是一个微不足道的对象,你只需要一个简单的副本:

    Thing thing1 = new Thing(arg1, arg2, arg3, arg4);
    Thing thing2 = (Thing)thing1.MemberwiseClone();
    
        4
  •  1
  •   gingerbreadboy    15 年前

    你可以重写 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]);
            }
        }
    
        5
  •  1
  •   Mark Simpson    15 年前

    我建议调查一下 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();
    
        6
  •  1
  •   Gilles 'SO- stop being evil'    13 年前

    使用 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)
    
        7
  •  0
  •   Hamish Grubijan    15 年前

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

    推荐文章