Ограничить количество параметров на метод? - PullRequest
13 голосов
/ 03 июня 2010

Предполагая, что все параметры имеют одинаковый тип, существует ли эмпирическое правило в отношении количества параметров для метода? Мне просто интересно, где мне провести черту и каковы мои альтернативы (например, интерфейс, массив и т. Д.).

Ответы [ 5 ]

9 голосов
/ 03 июня 2010

Стив Макконнелл рассматривает это в Code Complete , ссылаясь на исследования, которые показывают, что люди не могут обрабатывать более семи кусков информации за раз, что делает семь общепринятым пределом везде, где это возможно.

В заключительном абзаце этого раздела (стр. 178 во втором издании) он пишет:

Если вы обнаружите себя постоянно передавая несколько аргументов, связь между вашими процедурами слишком плотно ... Если вы проходите то же самое данные для многих различных подпрограмм, группа процедуры в класс и лечить часто используемые данные в качестве класса данные.

7 голосов
/ 03 июня 2010

Я бы сказал, это действительно зависит от вашего случая. Ты что-то делаешь со всем набором? Например, проверить все элементы или объединить данные? В этом случае я бы передал IEnumerable в качестве единственного параметра.

Передача большого количества параметров может быть хорошим признаком плохого разделения интересов (т. Е. Ваш метод делает слишком много), но в этом случае кажется, что вы передаете четко определенный набор элементов для их итерации. каким-то образом. Учитывая синтаксис инициализатора коллекции в C # 3, я бы рекомендовал IEnumerable практически во всех случаях для списка параметров, который был бы чем-то вроде Type a, Type b, Type c....

Конечно, если ваши параметры действительно обрабатываются по-разному, то их разделение имеет смысл, но я бы рассмотрел, что вы делаете в этом случае. Простым случаем, который приходит на ум, будет построение древовидной структуры данных и наличие функции для создания дочерних элементов узла. Плохой синтаксис может быть:

Node BuildTree( Node parent, Node child1, Node child2...)

Я бы, наверное, занялся чем-то вроде:

void ConstructChildren( this Node parent, IEnumerable<Node> children)

Если вы можете предоставить больше информации о вашем случае, и о том, какую логику вы выполняете для параметров, вероятно, будет легче увидеть, является ли это хорошим кандидатом для свертывания или рефакторинга.

3 голосов
/ 03 июня 2010

Я пытаюсь ограничить его до 4 или около того. Некоторые говорят меньше, другие говорят больше.

Альтернативой тоннам параметров было бы создание класса операций, т.е. замена:

func(boo, far, lint, pizza, flags);

с

var action = new DoSomethingObject(boo, far, lint);
action.Food = pizza;
action.Go(flags);

Это имеет несколько преимуществ перед функцией:

  • Если некоторые параметры являются необязательными, вы можете предоставить их в виде свойств (например, pizza выше).
  • Если ваша функция принимает столько аргументов, скорее всего, она делает много и может быть разбита на более мелкие функции. Класс поможет вам сделать это чисто.
2 голосов
/ 03 июня 2010

Если вы будете передавать неизвестное количество аргументов, вы должны использовать varargs или передать IEnumerable. Конечно, иногда вы передаете фиксированное количество предметов одного типа. В последнем случае фиксированное число должно следовать из цели метода.

1 голос
/ 03 июня 2010

Кроме того, для большей читаемости сайта вызовов вы можете использовать список параметров params (упомянутые выше переменные), поэтому вместо

void ConstructChildren( Node parent, IEnumerable<Node> children)
....
List<Node> children = new List<Node> {child1, child2, child3};
ConstructChildren(parent, children);

Я бы использовал

void ConstructChildren( Node parent, params Node[] children)
...
ConstructChildren( parent, child1, child2, child3);

Однако синтаксис params выглядит уродливым, если вы используете более 5-6-7 элементов в дочерней коллекции.

...