使用命名参数会有额外的运行时成本吗?

时间:2010-05-21 10:23:32

标签: c#-4.0

考虑以下结构:

    public struct vip
    {
        string email;
        string name;
        int category;

        public vip(string email, int category, string name = "")
        {
            this.email = email;
            this.name = name;
            this.category = category;
        }
    }

以下两个电话之间是否存在性能差异?

var e = new vip(email: "foo", name: "bar", category: 32);

var e = new vip("foo", 32, "bar");

如果没有定义可选参数会有区别吗?

5 个答案:

答案 0 :(得分:5)

我相信没有。它只是一种语言/编译器功能,如果你愿意,可以称它为语法糖。生成的CLR代码应该相同。

答案 1 :(得分:3)

有编译时的成本,但不是运行时成本......编译时间非常非常分钟。

extension methodsauto-implemented properties一样,这只是编译器的魔力,但实际上会生成相同的IL,我们都熟悉并且已经使用了多年。

以这种方式思考,如果你使用所有参数,编译器会使用所有参数调用方法,如果不是,它会在幕后产生类似的东西:

 var e = new vip(email: "foo", category: 32); //calling

 //generated, this is what it's actually saving you from writing
 public vip(string email, int category) : this(email, category, "bar") { }

答案 2 :(得分:1)

应该没有。基本上,命名参数和可选参数是语法糖;编译器将实际值或默认值直接写入调用站点。

编辑:请注意,因为它们是编译器功能,这意味着只有在重新编译“客户端”时才会更新参数更改。因此,例如,如果更改可选参数的默认值,则需要重新编译所有“客户端”,否则它们将使用旧的默认值。

答案 3 :(得分:1)

不,它只是一个编译时功能。如果检查生成的IL,您将看不到命名参数的迹象。同样,可选参数也是编译时功能。

关于命名参数要记住的一件事是,名称现在是编译时调用方法(如果明显使用)的签名的一部分。即如果名称发生更改,则重新编译时也必须更改调用代码。另一方面,部署的程序集在重新编译之前不会受到影响,因为IL中不存在名称。

答案 4 :(得分:1)

实际上,x64 CLR有成本

请看http://www.dotnetperls.com/named-parameters

我能够重现结果:命名调用需要4.43 ns,正常调用需要3.48 ns (程序在x64中运行)

然而,在x86中,两者都需要大约0.32 ns

代码附在下面,编译并自己运行以查看差异。

请注意,在VS2012中,默认的targat是AnyCPU x86首选,你必须切换到x64才能看到差异。

using System;
using System.Diagnostics;

class Program
{
    const int _max = 100000000;
    static void Main()
    {
    Method1();
    Method2();

    var s1 = Stopwatch.StartNew();
    for (int i = 0; i < _max; i++)
    {
        Method1();
    }
    s1.Stop();
    var s2 = Stopwatch.StartNew();
    for (int i = 0; i < _max; i++)
    {
        Method2();
    }
    s2.Stop();
    Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) /
        _max).ToString("0.00 ns"));
    Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) /
        _max).ToString("0.00 ns"));
    Console.Read();
    }

    static void Method1()
    {
    Method3(flag: true, size: 1, name: "Perl");
    }

    static void Method2()
    {
    Method3(1, "Perl", true);
    }

    static void Method3(int size, string name, bool flag)
    {
    if (!flag && size != -1 && name != null)
    {
        throw new Exception();
    }
    }
}
相关问题