38

使用 params 关键字与 List 作为某些 c# 函数的输入的优缺点是什么?

主要是性能考虑和其他权衡。

4

9 回答 9

41

params 关键字是由 C# 编译器处理的语法糖。在引擎盖下,它实际上在转动

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

进入

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

从您所询问的性能角度来看,params 调用速度更快,因为创建数组比创建 List<> 快一点。上面的两个片段之间没有性能差异。

于 2010-01-22T03:08:21.733 回答
27

我个人在编写接受其他程序员params提供的大量输入的函数时使用(例如),以及在编写接受计算机提供的数据项列表的函数时(例如)。String.FormatIEnumerableFile.Write

性能影响可以忽略不计。担心这样一件微不足道的事情的性能正是Donald Knuth 在著名的“过早优化是万恶之源”中所说的。

也就是说,提问者似乎很关注它,所以你去吧:

1000 万次迭代的结果:

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);
    }
}
于 2010-01-22T02:44:29.107 回答
3

好吧,使用 params 关键字,您可以将参数输入到这样的方法中:

MethodName(1, 2, 3, 4);

但是有了一个列表,你会这样做:

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

前者的语法比后者更清晰一些。当您只需要传入一个参数时,这很有用:

// params
MethodName(1);

// List
MethodName(new List<int> {1});
于 2010-01-22T01:26:31.980 回答
2

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% 确定,但我认为技术差异只是语法糖——在任何一种情况下,你都在传递一个数组键入参数是。

于 2010-01-22T01:24:58.083 回答
2

好吧,params在调用它时允许使用更好的语法,但是列表(假设您的意思是IList<>)更灵活,因为不同的类可能实现接口。List<>仅当您需要对列表执行接口不支持的特定操作(例如)时,传递 a才有意义ToArray()

于 2010-01-22T01:27:40.797 回答
0

params是采用可变数量参数的函数的语言结构。它类似于 C 省略说明符 - 即printf(char* fmt, ...)。该语言支持这种操作,不妨使用它,尤其是如果它使代码更易于阅读。

于 2010-01-22T01:29:00.303 回答
0

就个人而言,我会跳过参数。我被它咬过一两次。如何?让我解释。

您使用此签名编写一个公共方法:

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");
于 2010-01-22T01:32:50.653 回答
0

我可以看到两者之间的主要区别是传递给方法的参数数量是在编译时使用设置的params,而使用 aList<T>它取决于在运行时传入的列表。

修复在编译时必须调用方法的参数数量是利还是弊,完全取决于您的设计和意图。根据您希望实现的目标,两者都可能是有益的。

Params在可读性方面有所帮助,并且与您将在 C# 中使用的可选参数一样接近。List<T>如果我需要在任何时候使用未知数量的参数,我只会亲自使用该实现。

编辑:刚刚发现您对性能问题的编辑。关于那个话题我不确定,虽然如果你可能期望使用大量的“参数” List<T>,而params由于它们必须被编码,它有一个理智的上限。

于 2010-01-22T01:33:01.833 回答
0

调用你的方法的程序员的性能有时可以通过你使用 params 关键字来提高。

(鉴于程序员的成本比计算机高得多,你为什么要考虑任何其他类型的性能。)

于 2011-06-21T12:11:28.877 回答