C #: ключевое слово params против списка - PullRequest
33 голосов
/ 22 января 2010

Каковы плюсы / минусы использования ключевого слова params и List в качестве входных данных для некоторой функции c #?

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

Ответы [ 9 ]

36 голосов
/ 22 января 2010

Ключевое слово params - синтаксический сахар, обрабатываемый компилятором C #. под капотом он на самом деле поворачивается

void Foo(params object[] a) { ... }
Foo(1,2,"THREE");

в

void Foo(object[] a) { ... }
Foo(new object[] { 1, 2, "THREE" })

С точки зрения производительности , как вы и просили, вызов params просто быстрее, потому что создать массив немного быстрее, чем создать список <>. Нет никакой разницы в производительности между двумя фрагментами выше.

24 голосов
/ 22 января 2010

Лично я использую params при написании функций, которые принимают ряд входных данных, предоставленных другим программистом (например, String.Format), и IEnumerable при написании функций, которые принимают список элементов данных компьютер (например, File.Write).

Значения производительности незначительны. Беспокойство по поводу производительности тривиальной вещи, подобной этой, является точно , о котором говорил Дональд Кнут в известной цитате «преждевременная оптимизация - корень всего зла».

Тем не менее, спрашивающий, кажется, зациклен на этом, так что вот вам:

Результаты для 10 миллионов итераций:

params took 308 ms
list took 879 ms

Из этих результатов мы можем видеть, что массив params более чем в два раза быстрее. Тот простой факт, что вы можете вызвать любую из этих вещей десять миллионов раз в секунду, означает, что вы совершенно напрасно тратите свое время, беспокоясь об этом. Используйте все, что подходит вашему коду лучше всего.

Код для его тестирования (скомпилирован и запущен в режиме выпуска с использованием VS2008)

class Program
{
    const int COUNT = 10000000;

    static IEnumerable<string> m_value = null;

    static void ParamsMethod(params string[] args)
    { m_value = args; } // do something with it to stop the compiler just optimizing this method away

    static void ListMethod(List<string> args)
    { m_value = args; } // do SOMETHING with it to stop the compiler just optimizing this method away

    static void Main(string[] args)
    {
        var s = new Stopwatch();
        s.Start();
        for (int i = 0; i < COUNT; ++i)
            ParamsMethod("a", "b", "c");

        Console.WriteLine("params took {0} ms", s.ElapsedMilliseconds);

        s.Reset();
        s.Start();
        for (int i = 0; i < COUNT; ++i)
            ListMethod(new List<string> { "a", "b", "c" });

        Console.WriteLine("list took {0} ms", s.ElapsedMilliseconds);
    }
}
2 голосов
/ 22 января 2010

Что ж, params допускает более приятный синтаксис при его вызове, но список (при условии, что вы имеете в виду IList<>) более гибок, поскольку различные классы могут реализовывать интерфейс. Передача List<> имеет смысл, только если вам нужно выполнить определенные операции со списком, которые не поддерживаются интерфейсом (например, ToArray()).

2 голосов
/ 22 января 2010

Ключевое слово params позволяет вам динамически передавать переменное число аргументов функции, не беспокоясь об ошибках компиляции, таких как:

public string PrefixFormatString(string p, string s, params object[] par)
{ 
    return p + string.Format(s, par);
}
...
PrefixFormatString("COM", "Output Error #{0} - Error = {1}", errNum, errStr);

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

public string PrefixFormatString(string p, string s, List<object> par)
{ 
    return p + string.Format(s, par.ToArray());
}
...
List<object> l = new List<object>(new object[] { errNum, errStr });
PrefixFormatString("COM", "Output Error #{0} - Error = {1}", l);

и имеет тенденцию скрывать значение того, какого типа данные ожидает функция.

Обратите внимание, что это очень похоже на передачу простой переменной массива. Единственное отличие состоит в том, что компилятор зафиксирует параметры в массиве для вас ... Я не уверен на 100%, но я думаю, что техническое различие - просто синтаксический сахар - в любом случае вы действительно передаете массив чего угодно введите параметр.

1 голос
/ 22 января 2010

Ну, с помощью ключевого слова params вы можете ввести аргументы в метод, подобный этому:

MethodName(1, 2, 3, 4);

Но со списком вы бы сделали это так:

MethodName(new List<int> {1, 2, 3, 4});

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

// params
MethodName(1);

// List
MethodName(new List<int> {1});
0 голосов
/ 21 июня 2011

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

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

0 голосов
/ 22 января 2010

Основное различие между этими двумя параметрами, которое я вижу, состоит в том, что число параметров, передаваемых в метод, устанавливается во время компиляции с помощью params, тогда как для List<T> это зависит от списка, переданного во время выполнения.

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

Params помогает в области читабельности и настолько близок к необязательному параметру, к которому вы собираетесь обратиться в C #. Я бы использовал реализацию List<T> только в том случае, если бы мне потребовалось неизвестное количество параметров в любой точке.

Редактировать: только что заметил ваши изменения в отношении проблем с производительностью. В этом вопросе я не уверен, хотя если бы вы могли ожидать большого количества «параметров», используя List<T>, тогда как params имеет ограничение по здравомыслию из-за необходимости кодирования.

0 голосов
/ 22 января 2010

Лично я бы пропустил параметры. Я был укушен один или два раза. Как? Позвольте мне объяснить.

Вы пишете публичный метод с этой подписью:

public static void LogInUser(string username, string password, params string[] options)

Вы тестируете это, оно работает, все готово ... и другая сборка / приложение вызывает вашу функцию.

Теперь, через месяц, вы хотите изменить свою подпись, добавив роль пользователя:

public static void LogInUser(string username, string password, string role, params string[] options)

О, как все изменилось для всего, что вызывает ваш метод.

LogInUser("z@z.com", "zz", "Admin", "rememberMe", "800x600");
0 голосов
/ 22 января 2010

params - языковая конструкция для функций, принимающих переменное число параметров. Это похоже на спецификатор C elipses - т.е. printf(char* fmt, ...). Язык поддерживает этот тип операций, может также использовать его, особенно если он облегчает чтение кода.

...