Зачем использовать ключевое слово params? - PullRequest
317 голосов
/ 28 сентября 2011

Я знаю, что это основной вопрос, но я не смог найти ответ.

Зачем его использовать? если вы напишите функцию или метод, который ее использует, то при удалении ее код все равно будет работать идеально, на 100% без него. Например:

С параметрами:

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

Без параметров:

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}

Ответы [ 8 ]

459 голосов
/ 28 сентября 2011

С помощью params вы можете вызывать свой метод следующим образом:

addTwoEach(1, 2, 3, 4, 5);

Без params вы не сможете.

Кроме того, вы можете вызывать метод с массивом в качестве параметра в обоих случаях :

addTwoEach(new int[] { 1, 2, 3, 4, 5 });

То есть params позволяет использовать ярлык при вызове метода.

Вне зависимости, вы можете резко сократить свой метод:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}
88 голосов
/ 28 сентября 2011

Использование params позволяет вызывать функцию без аргументов.Без params:

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

Сравните с params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

Обычно вы можете использовать params, когда число аргументов может варьироваться от 0 до бесконечности, и использоватьмассив, когда число аргументов варьируется от 1 до бесконечности.

21 голосов
/ 28 сентября 2011

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

addTwoEach(10, 2, 4, 6)

, тогда как во второй форме вы должны использовать массив в качестве параметра

addTwoEach(new int[] {10,2,4,6})
15 голосов
/ 30 июня 2015

Одна опасность с params Ключевым словом, если после Закодированы вызовы метода,

  1. кто-то случайно / преднамеренно удаляет один / несколько обязательных параметров из подписи метода, и
  2. один / более требуется Параметры непосредственно перед параметром params до изменения подписи совместимы по типу с параметром params,

эти вызовы будут продолжать компилироваться с одним / несколькими выражениями, ранее предназначенными для обязательных параметров, обрабатываемых как необязательный params параметр. Я столкнулся с наихудшим из возможных случаев: параметр params имел тип object[].

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

Для меня это не стоит ярлыка. (Type)[] без params будет работать с параметрами от 0 до бесконечности # без необходимости переопределений. В худшем случае вам нужно будет добавить , new (Type) [] {} к звонкам, если это не применимо.

Кстати, имхо, самая безопасная (и наиболее читаемая) практика:

  1. проходят через именованные параметры (что мы можем теперь сделать даже в C # ~ 2 десятилетия после того, как мы могли бы в VB; P) (потому что:

    1,1. это только способ, которым гарантирует предотвращение непреднамеренных значений, передаваемых в параметры после порядка параметров, типа Compatible-Type и / или счетчика после кодирования вызовов,

    * * 1.2 тысяча сорок-девять. это уменьшает эти шансы после изменения значения параметра, поскольку вероятное имя нового идентификатора, отражающее новое значение, находится прямо рядом со значением, передаваемым ему,

    1,3. он избегает необходимости считать запятые и переходить назад и вперед от Call to Signature, чтобы увидеть, какое выражение передается для какого параметра, и

    1.3.1. Кстати, одна только эта причина должна быть много (с точки зрения избежания частых, подверженных ошибкам нарушений Принципа СУХИ только для чтения кода, не говоря уже о модификации it), но эта причина может быть экспоненциально более важной, если имеется одно / несколько передаваемых выражений, которые сами содержат запятые, то есть ссылки на многомерный массив или многопараметрические вызовы функций. В этом случае вы даже не могли бы использовать (что даже если бы вы могли добавить дополнительный шаг на Параметр на вызов метода) функцию Найти все вхождения в функции выбора в вашем редакторе, чтобы автоматизировать подсчет запятой для вас.

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

(ПРИМЕЧАНИЕ. Причины 1.2. И 1.3. Могут облегчить и уменьшить вероятность ошибок даже при кодировании исходных вызовов, не говоря уже о том, когда вызовы должны быть прочитаны и / или изменены.))

и

  1. сделать это ОДИН - ПАРАМЕТР - НА - ЛИНИЮ для лучшей читаемости (потому что:

    2,1. это менее загромождено, и

    2,2. он избегает необходимости прокручивать вправо и назад влево (и это необходимо делать PER - LINE, поскольку большинство смертных не могут прочитать левую часть нескольких строк, прокрутить вправо и прочитать правую часть)).

    2,3. это согласуется с «Лучшей практикой», в которую мы уже вошли для операторов присваивания, потому что каждый переданный параметр по сути является оператором присваивания (присваивая значение или ссылку на локальную переменную). Точно так же, как те, кто следит за последней «Лучшей практикой» в стиле кодирования, не будут мечтать о кодировании нескольких операторов присваивания на строку, мы, вероятно, не должны (и не будем однажды «Лучшая практика» ). догоняет моего "гения"; P) делайте это при передаче параметров.

ПРИМЕЧАНИЯ :

  1. Передача переменных, имена которых соответствуют параметрам, не помогает, когда:

    1,1. вы передаете литеральные константы (т. е. простые 0/1, false / true или null, для которых даже в «Best Practices» может не потребоваться использование именованной константы, и их назначение не может быть легко определено из имени метода ),

    1.2. Метод является значительно более низким уровнем / более общим, чем вызывающий, так что вы не захотите / не сможете назвать ваши переменные такими же / похожими на параметры (или наоборот), или

    1,3. вы переупорядочиваете / заменяете параметры в подписи, что может привести к тому, что предыдущие вызовы все еще компилируются, поскольку типы оказываются все еще совместимыми.

  2. Наличие функции автоматического переноса, подобной VS, исключает только ОДНУ (# 2.2) из ​​8 причин, которые я привел выше. До VS 2015 года это НЕ делало авто-отступ (!?! Действительно, MS?!?), Что увеличивает серьезность причины # 2.1.

VS должен иметь опцию, которая генерирует фрагменты вызова метода с именованными параметрами (по одному на строку, конечно, P) и опцию компилятора, для которой требуется Именованные параметры (в принципе аналогично Option Explicit в VB, который, между прочим, требование когда-то считалось столь же возмутительным, но теперь требуется *1119* в соответствии с "" передовой практикой "). На самом деле, «назад в мой день»;), в 1991 году, за несколько месяцев до моей карьеры, даже до того, как я использовал (или даже видел) язык с именованными параметрами, у меня был анти-овец / «просто потому, что вы можете, не значит, что вы должны» / не слепо «резать концы жаркого» достаточно, чтобы смоделировать его (используя встроенные комментарии), не видя, чтобы кто-то делал это. Отсутствие необходимости использовать именованные параметры (а также другой синтаксис, сохраняющий «драгоценные» нажатия клавиш исходного кода) является пережитком эры перфокарт, когда началось большинство этих синтаксисов. Этому нет оправдания современному оборудованию и IDE, а также гораздо более сложному программному обеспечению, в котором удобочитаемость гораздо, MUCH важнее. «Код читается гораздо чаще, чем пишется». Если вы не дублируете не-автоматически обновляемый код, каждое сохраненное нажатие клавиш, вероятно, будет стоить экспоненциально дороже, если кто-то (даже вы) попытаетесь прочитать его позже.

9 голосов
/ 31 марта 2014

Нет необходимости создавать методы перегрузки, просто используйте один единственный метод с параметрами, как показано ниже

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);
4 голосов
/ 18 января 2014

Добавление ключевого слова params само по себе показывает, что при вызове этого метода вы можете передать несколько параметров, что невозможно без его использования.Чтобы быть более конкретным:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

Когда вы будете вызывать вышеуказанный метод, вы можете вызвать его любым из следующих способов:

  1. addTwoEach()
  2. addTwoEach(1)
  3. addTwoEach(new int[]{ 1, 2, 3, 4 })

Но при удалении ключевого слова params только третий способ из приведенных выше способов будет работать нормально.Для 1-го и 2-го случая вы получите ошибку.

4 голосов
/ 28 сентября 2011

params также позволяет вызывать метод с одним аргументом.

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

т.е. Foo(1); вместо Foo(new int[] { 1 });. Может быть полезно для сокращения в сценариях, где вам может потребоваться передать одно значение, а не весь массив. Он по-прежнему обрабатывается так же, как в методе, но дает некоторую конфету для вызова таким образом.

0 голосов
/ 14 июля 2019

Необходимо подчеркнуть еще одну важную вещь Лучше использовать params, потому что это лучше для производительности. Когда вы вызываете метод с params аргументом и ничего не передаете ему:

public void ExampleMethod(params string[] args)
{
// do some stuff
}

звоните:

ExampleMethod();

Затем новые версии .Net Framework делают это (из .Net Framework 4.6):

ExampleMethod(Array.Empty<string>());

Этот Array.Empty объект может быть повторно использован платформой позже, поэтому нет необходимости делать избыточные выделения. Это распределение произойдет, когда вы вызовете этот метод следующим образом:

 ExampleMethod(new string[] {});
...