C#:params关键字与列表

时间:2010-01-22 01:18:54

标签: c# optimization list params

使用params关键字与List作为某些c#函数的输入有什么利弊?

主要是什么是效果注意事项和其他权衡因素。

9 个答案:

答案 0 :(得分:36)

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

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

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

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

答案 1 :(得分:24)

我个人在编写函数时使用params,这些函数接受另一个程序员(例如String.Format)提供的大量输入,并且在编写函数时使用IEnumerable获取计算机提供的数据项列表(例如File.Write)。

性能影响可以忽略不计。担心像这样的琐碎事情的表现是完全唐纳德克努特在着名的“过早优化是所有邪恶的根源”中引用的内容。

那就是说,提问者似乎已经注意到了,所以你走了:

1000万次迭代的结果:

params took 308 ms
list took 879 ms

从这些结果中我们可以看到params数组的速度快了两倍。一个简单的事实是你可以在一秒钟之内调用 1000万次中的任何一个,这意味着你会因为担心而浪费你的时间。使用最适合您代码的任何内容。

测试它的代码(使用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 :(得分: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%肯定,但我认为技术差异只是语法糖 - 在任何一种情况下你都真的传递了一系列的输入参数是。

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

MethodName(1, 2, 3, 4);

但是有一个列表,你可以这样做:

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

前者的语法可能比后者更清晰。当您只传入一个参数时,这非常有用:

// params
MethodName(1);

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

答案 5 :(得分:0)

params是用于获取可变数量参数的函数的语言构造。它类似于C elipses说明符 - 即printf(char* fmt, ...)。该语言支持这种操作,也可以使用它,特别是如果它使代码更容易阅读。

答案 6 :(得分: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");

答案 7 :(得分:0)

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

是否修复在编译时必须调用方法的参数数量是pro还是con,完全取决于你的设计和意图。根据您希望实现的目标,这两者都可以是一种好处。

Params有助于提高可读性,并且与C#中的可选参数非常接近。如果我需要在任何时候使用未知数量的参数,我只会亲自使用List<T>实现。

编辑:刚发现有关性能问题的编辑。关于该主题,我不确定,尽管如果您可能期望使用List<T>获得大量“参数”,而params则因为必须对其进行编码而具有理智上限。

答案 8 :(得分:0)

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

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