问候!我对C#编译器如何执行其优化感到有些困惑。
我编写了以下getter来组成“惰性”初始化,如果为null,则使用默认值:
静态类助手:
private static string host;
public static string Host
{
get
{
return host ?? (host= (ConfigurationManager.AppSettings["Host"] ?? "host.ru"));
}
}
这是Reflector拆卸的结果:
public static string Host
{
get
{
if (Helper.host == null)
{
string host = Helper.host;
}
return (Helper.host = ConfigurationManager.AppSettings["Host"] ?? "host.ru");
}
}
看起来它可以以其他方式工作...
更新
private static string host;
public static string Host
{
get
{
return host ?? (host = (GetVal() ?? "default"));
}
}
static void Main(string[] args)
{
Console.WriteLine(Host);
host = "overwritten";
Console.WriteLine(Host);
}
static string GetVal()
{
return "From config";
}
正常工作(从配置中覆盖),但是Reflector显示相同:
public static string Host
{
get
{
if (Program.host == null)
{
string host = Program.host;
}
return (Program.host = GetVal() ?? "default");
}
}
最佳答案
这看起来像是Reflector的C#反汇编中的错误。
从以下代码开始:
public static string _test;
public static string _setting;
public static string Test_1
{
get { return _test ?? (_setting ?? "default"); }
}
Reflector显示此C#反汇编:
public static string Test_1
{
get
{
return (_test ?? (_setting ?? "default"));
}
}
以及相应的IL:
.method public hidebysig specialname static string get_Test_1() cil managed
{
.maxstack 8
L_0000: ldsfld string ConsoleApplication1.Program::_test
L_0005: dup
L_0006: brtrue.s L_0017
L_0008: pop
L_0009: ldsfld string ConsoleApplication1.Program::_setting
L_000e: dup
L_000f: brtrue.s L_0017
L_0011: pop
L_0012: ldstr "default"
L_0017: ret
}
我不是IL专家,但这是我的看法:
L_0000:
ldsfld
将_test
推送到评估堆栈L_0005:
dup
复制评估堆栈上最顶部的值(_test
),并将其压入堆栈。L_0006:
brtrue.s
将dup
创建的值弹出堆栈,如果不是L_0017
,则跳转到null
。L_0008:
pop
此时,_test
是null
,因此将该值弹出堆栈。并继续以类似的方式评估
_setting
,如果"default"
也是_setting
,则最终返回null
。现在,如果我们将赋值添加到代码中,如下所示:
public static string Test_2
{
get { return _test ?? (_test = (_setting ?? "default")); }
}
Reflector显示此C#反汇编:
public static string Test_2
{
get
{
if (_test == null)
{
string text1 = _test;
}
return (_test = _setting ?? "default");
}
}
这是不正确的(如果
_test
不是null
,而不是返回_test
,而是将_setting
或"default"
分配给_test
,然后返回)。但是,IL反汇编看起来像
Test_1
的IL,在L_0017
和L_0018
处有一些额外的指令来执行分配。.method public hidebysig specialname static string get_Test_2() cil managed
{
.maxstack 8
L_0000: ldsfld string ConsoleApplication1.Program::_test
L_0005: dup
L_0006: brtrue.s L_001d
L_0008: pop
L_0009: ldsfld string ConsoleApplication1.Program::_setting
L_000e: dup
L_000f: brtrue.s L_0017
L_0011: pop
L_0012: ldstr "default"
L_0017: dup
L_0018: stsfld string ConsoleApplication1.Program::_test
L_001d: ret
}
最后,如果您复制Reflector的C#反汇编并针对原始反汇编运行,您会看到它产生不同的结果。
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
_test = "Test";
Console.WriteLine(Test_2);
Console.WriteLine(Reflector_Test_2);
Console.ReadLine();
}
public static string _test;
public static string _setting;
public static string Test_1
{
get { return _test ?? (_setting ?? "default"); }
}
public static string Test_2
{
get { return _test ?? (_test = (_setting ?? "default")); }
}
public static string Reflector_Test_2
{
get
{
if (_test == null)
{
string text1 = _test;
}
return (_test = _setting ?? "default");
}
}
}
}
产出
Test
default
关于c# - C#编译优化:空合并运算符-更新-Reflector的错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4292142/