Given the two methods:
static void M1(Person p)
{
if (p != null)
{
var p1 = p.Name;
}
}
static void M2(Perso
Start with the fact that callvirt
is used instead of call
because of the C# rule that null objects may not have methods called on them, even when .NET allows it.
Now, in both your methods, we can show statically that p
is not null, and as such using call
instead of callvirt
is not going to break this C# rule, and as such is a reasonable optimisation.
While if (a != null) a.b
etc. is a common idiom, it takes analysis to realise that a
cannot be null at the point that b
is used. Adding that analysis to the compiler would take work specing, implementing, testing, and continually testing against regression bugs introduced by other changes.
a?.b
is beyond an idiom, in that it's using an operator ?.
that C# must "know" about. So C# has to have the code to turn this into a null check followed by a member access. So the compiler has to know that at the point where the member access happens, a
is not null. As such the logic to "know" the use of call
is safe has already been done. It's no extra analysis work to realise that call
can be used.
So the first case would require a bunch of extra work to use call
and potentially introduce bugs, while the second case has to do that work anyway, so it might as well.