У меня есть эта функция API:
public ResultEnum DoSomeAction(string a, string b, DateTime c, OtherEnum d,
string e, string f, out Guid code)
Мне это не нравится Потому что порядок параметров становится излишне значимым. Становится сложнее добавлять новые поля. Труднее увидеть, что происходит вокруг. Сложнее реорганизовать метод в более мелкие части, поскольку он создает дополнительные издержки, связанные с передачей всех параметров в подфункции. Код сложнее читать.
Я пришел к наиболее очевидной идее: иметь объект, инкапсулирующий данные, и передавать его вместо передачи каждого параметра один за другим. Вот что я придумал:
public class DoSomeActionParameters
{
public string A;
public string B;
public DateTime C;
public OtherEnum D;
public string E;
public string F;
}
Это уменьшило мою декларацию API до:
public ResultEnum DoSomeAction(DoSomeActionParameters parameters, out Guid code)
Ницца. Выглядит очень невинно, но мы действительно внесли огромное изменение: мы ввели изменчивость. Потому что раньше мы фактически передавали анонимный неизменяемый объект: параметры функции в стеке. Теперь мы создали новый класс, который очень изменчив. Мы создали возможность манипулировать состоянием звонящего . Это отстой. Теперь я хочу, чтобы мой объект был неизменным, что мне делать?
public class DoSomeActionParameters
{
public string A { get; private set; }
public string B { get; private set; }
public DateTime C { get; private set; }
public OtherEnum D { get; private set; }
public string E { get; private set; }
public string F { get; private set; }
public DoSomeActionParameters(string a, string b, DateTime c, OtherEnum d,
string e, string f)
{
this.A = a;
this.B = b;
// ... tears erased the text here
}
}
Как видите, я на самом деле заново создал свою первоначальную проблему: слишком много параметров. Очевидно, что это не тот путь. Что я собираюсь делать? Последний вариант для достижения такой неизменности - использовать структуру «только для чтения», например:
public struct DoSomeActionParameters
{
public readonly string A;
public readonly string B;
public readonly DateTime C;
public readonly OtherEnum D;
public readonly string E;
public readonly string F;
}
Это позволяет нам избегать конструкторов со слишком большим количеством параметров и достигать неизменности. На самом деле это решает все проблемы (упорядочение параметров и т. Д.). Все же:
- Все (включая FXCop и Jon Skeet) согласны с тем, что показ открытых полей плох .
- Эрик Липперт и др. Говорят, что полагаться на поля только для чтения для неизменности - ложь .
Вот тогда я запутался и решил написать вопрос: какой самый простой способ в C # избежать проблемы «слишком много параметров» без введения изменчивости? Возможно ли использовать структуру readonly для этой цели и при этом не иметь плохой дизайн API?
ПОЯСНЕНИЯ:
- Пожалуйста, примите во внимание, что нет нарушения принципа единой ответственности. В моем исходном случае функция просто записывает данные параметры в одну запись БД.
- Я не ищу конкретного решения данной функции. Я ищу обобщенный подход к таким проблемам. Я особенно заинтересован в решении проблемы «слишком много параметров» без введения изменчивости или ужасного дизайна.
ОБНОВИТЬ
Ответы, представленные здесь, имеют различные преимущества / недостатки. Поэтому я хотел бы преобразовать это в вики сообщества. Я думаю, что каждый ответ с примером кода и преимуществами и недостатками мог бы стать хорошим руководством для решения подобных проблем в будущем. Я сейчас пытаюсь выяснить, как это сделать.
DoSomeActionParameters
это одноразовый объект, который будет отброшен после вызова метода.