I struggle with the CIL disassembly of the parameter to the WriteLine()
call in:
FileInfo path = new FileInfo(@"c:\a.txt");
Console.WriteLine("prefix: " + path != null ? path.FullName : "null");
CIL dissasembly
.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)
It seems to me that Concat
is called first, and only then is the ternary
operator evaluated. In particular:
IL_0012
Concat("prefix", path)
seems to be called,
IL_0012
brtrue.s IL_0020
// branch based on the previous return value
Concat
called with path
as a parameter instead of path.FullName
?Concat
return null
, if its first parameter is null
? How does the
compiler know that? (If I replace +
with my own plus(string, string)
, the
disassembly to something I would rather expect.)Could you please explain, how the disassembly handles the ternary parameter and the call to WriteLine
?
It's not a problem of the disassembly, it's a problem of operator precedence.
Your expression is evaluated as
("prefix: " + path != null) ? path : "null";
Not as
"prefix: " + (path != null ? path : "null");
as you seem to expect. Just use parentheses correctly and you'll be fine :)
In fact, it's a missed "optimization" on part of the compiler - since string.Concat("prefix: ", whatever)
can never be null, you'll always get path.FullName
. Of course, a ternary that only ever evaluates to one of its options is almost certainly a bug, so...