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)