Gre*_*les 19 .net c# vb.net c#-4.0
现在C#支持命名参数,我正在检查它是否以与VB相同的方式实现,并发现存在细微差别.以这样的库函数为例:
public static void Foo(string a, string b)
{
Console.WriteLine(string.Format("a: {0}, b: {1}", a, b));
}
Run Code Online (Sandbox Code Playgroud)
在C#中,如果你这样称呼它:
Foo(a: "a", b: "b");
Run Code Online (Sandbox Code Playgroud)
编译器生成以下IL指令:
.locals init (
[0] string CS$0$0000,
[1] string CS$0$0001)
L_0000: nop
L_0001: ldstr "a"
L_0006: stloc.0
L_0007: ldstr "b"
L_000c: stloc.1
L_000d: ldloc.0
L_000e: ldloc.1
L_000f: call void [TestLibrary]TestLibrary.Test::Foo(string, string)
L_0014: nop
L_0015: ret
Run Code Online (Sandbox Code Playgroud)
这转换为以下C#代码:
string CS$0$0000 = "a";
string CS$0$0001 = "b";
Test.Foo(CS$0$0000, CS$0$0001);
Run Code Online (Sandbox Code Playgroud)
在VB中,如果你这样称呼它:
Foo(a:="a", b:="b")
Run Code Online (Sandbox Code Playgroud)
编译器生成以下IL指令:
L_0000: nop
L_0001: ldstr "a"
L_0006: ldstr "b"
L_000b: call void [TestLibrary]TestLibrary.Test::Foo(string, string)
L_0010: nop
L_0011: nop
L_0012: ret
Run Code Online (Sandbox Code Playgroud)
这转换为以下VB代码:
Foo("a", "b");
Run Code Online (Sandbox Code Playgroud)
VB的方式需要更少的指令调用,因此C#实现它的方式有什么优势吗?如果不使用命名参数,C#会生成与VB相同的内容.
编辑:现在我们已经确定额外的指令在发布模式下消失了,是否有一个特殊的原因让它们出现在调试模式中?VB在两种模式下的作用相同,并且C#在没有命名参数的情况下正常调用方法时不会插入额外的指令(包括使用可选参数时).
Eri*_*ert 13
是否有一个特殊的原因让他们出现在调试模式?
区别在于:
这种差异的明显效果是垃圾收集器不能像清理值那样积极.在第一种情况下,一旦呼叫返回,就可以立即收集该值.在第二种情况下,仅在当前方法返回(或重新使用插槽)之后收集该值.
使垃圾收集器不那么激进通常有助于调试方案.
隐含的问题是:
为什么C#和VB之间存在差异?
C#和VB编译器是由不同的人编写的,他们对各自的代码生成器的工作方式做出了不同的选择.
更新:回复:你的评论
在C#编译器中,未优化的IL生成与我们内部的特征表示基本上具有相同的结构.当我们看到一个命名参数时:
M(y : Q(), x : R());
Run Code Online (Sandbox Code Playgroud)
比如,方法在哪里
void M(int x, int y) { }
Run Code Online (Sandbox Code Playgroud)
我们在内部表示,就像你写的一样
int ytemp = Q();
int xtemp = R();
M(xtemp, ytemp);
Run Code Online (Sandbox Code Playgroud)
因为我们想要保持Q和R的副作用的从左到右的评估.这是一个合理的内部表示,当我们在非优化模式下编码时,我们只是直接从内部表示编码代码几乎没有修改.
当我们运行优化器时,我们会检测所有类型的东西 - 比如没有人使用那些不可见的局部变量.然后我们可以从codegen中消除本地人.
我对VB内部表示知之甚少; 我从1995年开始就没有使用VB编译器,我听说在过去的十五年里它可能只是略有改变.我想他们会做类似的事情,但我不知道他们如何代表命名参数或他们的代码生成器如何处理它们的细节.
我的观点是,据我所知,这种差异并不能说明一个重要的语义差异.相反,它说明了非优化构建只是吐出我们碰巧生成的任何高级内部表示,我们知道它具有所需的语义.
编译器生成以下C#代码:
否 - 编译器生成IL,然后将其转换为C#.与C#代码的任何相似之处纯属偶然(并非所有生成的IL 都可以写成C#).所有那些"nop"的存在告诉我你处于"调试"模式.我会在"发布"模式下重试 - 它可以对这些事情产生重大影响.
我在发布模式下将其启动,使用:
static void Main()
{
Foo(a: "a", b: "b");
}
Run Code Online (Sandbox Code Playgroud)
赠送:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 8
L_0000: ldstr "a"
L_0005: ldstr "b"
L_000a: call void ConsoleApplication1.Program::Foo(string, string)
L_000f: ret
}
Run Code Online (Sandbox Code Playgroud)
如此相同.
| 归档时间: |
|
| 查看次数: |
1640 次 |
| 最近记录: |