我在参与CIL反汇编参与WriteLine()
调用时遇到了困难:
FileInfo path = new FileInfo(@"c:\a.txt"); Console.WriteLine("prefix: " + path != null ? path.FullName : "null");
CIL解散
.locals init ( [0] class [mscorlib]System.IO.FileInfo path ) // ... IL_000c: ldstr "prefix: " IL_0011: ldloc.0 IL_0012: call string [mscorlib]System.String::Concat(object, object) IL_0017: brtrue.s IL_0020 IL_0019: ldstr "null" IL_001e: br.s IL_0026 IL_0020: ldloc.0 IL_0021: callvirt instance string [mscorlib]System.IO.FileSystemInfo::get_FullName() IL_0026: call void [mscorlib]System.Console::WriteLine(string)
在我看来,它Concat
首先被调用,然后才对三元运算符进行评估.特别是:
IL_0012
Concat("prefix", path)
似乎被调用, //基于先前的返回值进行分支
IL_0012
brtrue.s IL_0020
为什么Concat
调用path
as而不是path.FullName
?
是否Concat
返回null
,如果它的第一个参数是null
?编译器如何知道?(如果我+
用我自己的替换plus(string, string)
,拆卸到我宁愿期待的东西.)
你能解释一下,反汇编如何处理三元参数和调用WriteLine
?
这不是拆卸的问题,而是操作员优先级的问题.
您的表达式被评估为
("prefix: " + path != null) ? path : "null";
不是
"prefix: " + (path != null ? path : "null");
正如你所期待的那样.只需正确使用括号,你就可以了:)
事实上,这是对编译器的部分错过了"优化" -因为string.Concat("prefix: ", whatever)
可以永远为空,你会永远得到path.FullName
.当然,一个只评估其中一个选项的三元组几乎肯定是一个bug,所以...