C# 4.0 使用命名参数是否有额外的运行时成本?

C# 4.0 使用命名参数是否有额外的运行时成本?,c#-4.0,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;

考虑以下结构:

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

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

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

有编译时成本,但不是运行时成本……而且编译时间非常,非常分钟

就像or一样,这只是编译器的魔法,但实际上生成的IL与我们都熟悉并且已经使用多年的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") { }

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


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

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


关于命名参数,需要记住的一点是,这些名称现在是在编译时调用方法(如果明显使用)的签名的一部分。也就是说,如果名称改变了,那么如果重新编译,调用代码也必须改变。另一方面,部署的程序集在重新编译之前不会受到影响,因为名称不在IL中

实际上,x64 CLR是有成本的

看看这里

我能够重现结果:命名呼叫需要4.43纳秒,正常呼叫需要3.48纳秒 (程序在x64中运行)

但是,在x86中,两者都需要大约0.32纳秒

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

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();
    }
    }
}
请注意,在VS2012中,默认目标是首选的任何CPU 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();
    }
    }
}
使用系统;
使用系统诊断;
班级计划
{
const int_max=100000000;
静态void Main()
{
方法1();
方法2();
var s1=Stopwatch.StartNew();
对于(int i=0;i<\u max;i++)
{
方法1();
}
s1.停止();
var s2=Stopwatch.StartNew();
对于(int i=0;i<\u max;i++)
{
方法2();
}
s2.停止();
Console.WriteLine(((双精度)(s1.eassed.total毫秒*1000*1000)/
_最大);
Console.WriteLine(((双精度)(s2.eassed.total毫秒*1000*1000)/
_最大);
Console.Read();
}
静态void方法1()
{
Method3(标志:true,大小:1,名称:“Perl”);
}
静态void方法2()
{
方法3(1,“Perl”,真);
}
静态void Method3(int大小、字符串名称、bool标志)
{
如果(!flag&&size!=-1&&name!=null)
{
抛出新异常();
}
}
}

+1-从技术上讲,实际上是一种编译器功能(因为langauge没有说明它是如何实现的)。默认值也是一样。@TomTom:我认为这是一种语言功能——虽然语言没有指定如何实现它,但它确实指定了它的存在。任何不实现命名参数的编译器都不是兼容的C#4编译器。是和否-编译器可以动态地实现它,例如,我以一种缓慢的方式。不过,这里所做的是编译器的一种快速方法。编译阶段后不会对运行时产生影响。各位,很抱歉浪费了你们的时间。我应该多考虑一下,没有理由道歉。这是一个完全正确的问题。