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#?

7 ответов


Я имею в виду, вот это:

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

просто будьте осторожны закрытие семантика.


Ну, я думаю, вы можете использовать контейнер 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();

и вы получите свежий экземпляр каждый раз, каждый со своими собственными объектами недвижимости.


есть также это, предполагая, что ваш Thing1 является тривиальным объектом, и вам просто нужна мелкая копия:

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

вы могли бы переписать 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]);
        }
    }

Я бы предложил заглянуть в Построитель Тестовых Данных узор. Он работает очень хорошо, когда у вас есть много параметров, которые вы хотите изменить независимо, повторно использовать и так далее.

можно использовать свойства + инициализаторы объектов для "плоской" классы, или жидкий метод цепляя как альтернатива. Я играл с обоими, и у каждого есть свои преимущества.

преимущества:

  • вы можете захватить переменные/значения которые использовались для строительства объект
  • вы можете повторно использовать экземпляр builder, если значения она принимает простые типы и / или неизменяемый (типы значений, строки и т. д.)
  • вы можете варьировать каждый ctor параметр независимо без шума / дублирование кода делает тесты читайте действительно красиво, как, а не нужно помнить, какой 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();

использовать 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)

вы также можете использовать массив объектов и цикл for, если вам нужно сделать это много раз.