“C# emits .callvirt instructions, even if the method isn’t virtual. That forces a call site null check.” (Immo Landwerth on Twitter)
Posted by jpluimers on 2025/06/25
From a while back, which I initially missed because it was in the midst figuring out my ver increasing bowel problems leading up to all my cancer treatments, but still relevant:
[Wayback/Archive] Immo Landwerth @terrajobst@hachyderm.io on Twitter: “That’s why C# emits
.callvirtinstructions, even if the method isn’t virtual. That forces a call sitenullcheck.”
Except inside [Wayback/Archive] Extension Methods, referring to this will never return null.
Yes you can work around this using things like reflection, but the C# compiler will emit .callvirt for any method call which does an implicit null check by the caller which means you never have to check that in callees.
The above tweet quoted the first message of the [Wayback/Archive] Thread by @MStrehovsky on Thread Reader App on working around this .callvirt protection:
[Wayback/Archive] Michal Strehovský on Twitter: “1/5 A little know C#/.NET fact is that one can end up in a situation where `
this is null` evaluates totrue. One just needs a bit of reflection.”
…
5/5 .NET Native has an optimization that eliminates the entire method bodies on types that were never seen as allocated that also doesn’t play well with this. This makes a good party trick (if the parties you go to are like the parties I go to), but don’t do this in real code
Which in a 2015 comment to [Wayback/Archive] Observing a null this value had an almost identical hack:
Well
class Program
{
public void Test()
{
if (this == null)
Console.WriteLine("this is null!");
}
static void Main(string[] args)
{
Action<program> p_act = (Action<program>)typeof(Program).GetMethod("Test").CreateDelegate(typeof(Action<program>));
p_act(null);
Console.ReadLine();
}
}Delegates obtained with reflection are Magic ehe.
Such extension methods can have specific use cases as shown in another comment to that blog post:
Sometimes I *want* to allow a null `this`, so I do:
public static bool IsNullOrEmpty<t>(this IEnumerable<t> @this)
{
return @this == null || !@this.Any();
}(and overloads forICollectionandstring, as a micro-optimization).
Some interesting comments to the first Tweet:
- [Wayback/A] Jared Parsons on Twitter: “@terrajobst
blog.paranoidcoding.com/2015/03/11/observing-a-null-this.html“ - [Wayback/Archive] Marc Gravell on Twitter: “@terrajobst Isn’t the JIT currently being tweaked to devirtualize aggressively? ….” / Twitter
- [Wayback/Archive] Drew Noakes on Twitter: “@terrajobst
callvirtalso keeps binary compat if the target member changes to becomevirtual. This may not have been part of the rationale, but it is a nice property from time to time.”
–jeroen



Leave a comment