问候!我对C#编译器如何执行其优化感到有些困惑 我编写了以下getter来构成“lazy”初始化,并在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");
}
}
答案 0 :(得分:1)
这看起来像是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#dissembly并将其与原始文件一起运行,您会看到它会产生不同的结果。
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
答案 1 :(得分:0)
我想我不明白 - 两个代码示例都是同义词。
请记住,Reflector无法从编译器生成的IL重现您的确切语法。有时语法会有所不同,但代码的语义和含义将始终相同。