C#: ключевое слово params против списка

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

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

9 ответов


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

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

на

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

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


лично я использую 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);
    }
}

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


ключевое слово 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%, но я думаю, что техническая разница - это просто синтаксический сахар-в любом случае вы действительно передаете массив любого типа параметра.


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

MethodName(1, 2, 3, 4);

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

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

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

// params
MethodName(1);

// List
MethodName(new List<int> {1});

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


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

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

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");

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

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

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

Edit: просто заметил ваше редактирование по вопросам производительности. По этой теме я не уверен, хотя, если вы потенциально можете ожидать большое количество "параметров", используя List<T>, тогда как params имеет крышку здравомыслия на нем из-за того, что они должны быть закодированный.


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

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