C# 为什么在函数中使用名称参数会产生更多的代码?

C# 为什么在函数中使用名称参数会产生更多的代码?,c#,performance,c#-4.0,compiler-construction,C#,Performance,C# 4.0,Compiler Construction,阅读Jon Skeet的书,我发现(现在有一段时间)在函数调用中使用了“命名参数”。下面是一个快速简单的示例: void Dump(int x, int y, int z, string cSomeText) { // no use, just to see how we call this later string cOnMe = string.Format("[{0}] [{1}] [{2}] [{3}]", x, y, z, cSomeText); } void Call

阅读Jon Skeet的书,我发现(现在有一段时间)在函数调用中使用了“命名参数”。下面是一个快速简单的示例:

void Dump(int x, int y, int z, string cSomeText)
{
    // no use, just to see how we call this later
    string cOnMe = string.Format("[{0}] [{1}] [{2}] [{3}]", x, y, z, cSomeText);
}

void CallDumpWithoutNameArguments()
{
    // call with out Name Arguments
    Dump(1, 2, 3, "Test string");
}

void CallDumpWithNameArguments()
{ 
    // more easy to read, call the same function with Name Arguments
    Dump(x: 1, y: 2, z: 3, cSomeText: "Test string");
}
在使用它之后,以及后来看到编译后的代码,我发现使用这个名称实际上是在调用函数之前创建变量的

这是创建的代码:

private void CallDumpWithoutNameArguments()
{
    this.Dump(1, 2, 3, "Test string");
}

private void CallDumpWithNameArguments()
{
    int CS$0$0000 = 1;
    int CS$0$0001 = 2;
    int CS$0$0002 = 3;
    string CS$0$0003 = "Test string";
    this.Dump(CS$0$0000, CS$0$0001, CS$0$0002, CS$0$0003);
}
完整的编译代码,你看我用“命名参数”来称呼它有多大

这是c#忘记优化的一点,或者它们还有其他用途吗

跟进 我想澄清的是,上面的代码是编译产生的。下面是我从Servy那里得到的答案

private void CallDumpWithoutNameArguments()
{
    // what generated from
    // int i = 0;
    // Dump(i++, i++, i++, cSomeText: "Test string");

    int i = 0;
    string CS$0$0000 = "Test string";
    this.Dump(i++, i++, i++, CS$0$0000);
} 

private void CallDumpWithNameArguments()
{
    // what is generate from
    // int i = 0;
    // Dump(x: i++, z: i++, y: i++, cSomeText: "Test string");

    int i = 0;
    int CS$0$0000 = i++;
    int CS$0$0001 = i++;
    int CS$0$0002 = i++;
    string CS$0$0003 = "Test string";
    this.Dump(CS$0$0000, CS$0$0002, CS$0$0001, CS$0$0003);
}

这与确保代码以正确的顺序运行有关。对于命名参数,每个参数的表达式需要按照它们在源代码中出现的顺序执行,而不是按照它们在定义的实际参数列表中出现的顺序执行。想象一下(非常刻薄的)电话:

最终是否应与以下内容相同:

Dump(0, 1, 2, "Test string");

如果没有每个命名参数的局部变量,则以第一个参数结束,如果有,则以第二个参数结束


看起来,与其试图确定是否有必要创建局部变量(参数是否无序,它们是否会产生副作用,这些副作用是否对其他参数中的表达式可见),不如始终创建局部变量更简单。在很多场合,C#编译器会确保正确性而不是优化;它为JIT留下了优化。

同样的代码用于调试和发布定义。我猜(为了它的价值)而不是当您使用命名参数时,编译器会为这些参数生成代码,而不是试图确定您是否按照声明的顺序命名参数。看看JIT也能做些什么会很有趣。@Albinsnanbo这是由JIT创建的。@Aristos JIT不创建IL,它会将IL编译为本机代码。如果有什么东西要做分析,看看它是否能在不破坏代码的情况下消除“伪”变量,我希望JITer能做到。我测试了这个,然后回来-好的,测试过了,我将用这个例子来更新这个问题。说实话,我更担心的是为什么要生成这么多的代码。@Aristos你的例子似乎证实了局部变量的作用是确保按从左到右的顺序观察参数表达式的副作用。这是语言规范的一个要求:必须按照从左到右的顺序计算表达式。但是,IL方法调用必须在正确的位置使用位置参数;局部变量协调了这两个相互冲突的需求。
int i = 0;
Dump(x: i++,  z: i++, y: i++, cSomeText: "Test string");
Dump(0, 1, 2, "Test string");
Dump(0, 2, 1, "Test string");