Is this null?
Today's post at the Daily WTF contains an interesting piece of code: a method that tests whether this is equal to null. Of course, doing that is silly. The value of this can never be null in C#, can it?
If you try to call an instance method on a null reference, a NullReferenceException is always thrown. Except this is not completely true. The exception is actually thrown only if the callvirt IL instruction is used. The alternative (at least for non-virtual methods) instruction call does not check for null. The C# compiler (and probably most other compilers for .Net languages) always emits the safe instruction for instance methods, so it seems we are actually safe.
The problem is, we can use IL directly. The easiest way is to create a DynamicMethod and use the unsafe instruction:
public class Program
{
static void Main()
{
var calledMethod = typeof(Program).GetMethod("IsThisNull");
var method = new DynamicMethod("testThisNull", typeof(bool), null);
var il = method.GetILGenerator();
// pushes null to the stack
il.Emit(OpCodes.Ldnull);
// uses the topmost item on the stack for this
il.Emit(OpCodes.Call, calledMethod);
// returns the result
il.Emit(OpCodes.Ret);
var result = method.Invoke(null, null);
}
public bool IsThisNull()
{
return this == null;
}
}
After this code runs, result is a boxed true and no exception was thrown. If we stopped debugger in the IsThisNull() method, we would see that this actually can be null!
The conclusion? While the daily WTF code, that checked whether this is null may theoretically have some reason to exist, it's not necessary in practice. If I was generating an IL to call an instance method, I would always use callvirt, just as C# does. And I suggest you do the same.
Discussion
linepogl
You did not have to go that far. In all extension methods "this" can be null.
porges
linepogl: There is no
thisin extension methods. There is athiskeyword which marks the fact that it is an extension method, but there is nothisreference.Jason W
C# didn't always emit only the "callvirt" instruction - it was changed between either 1.0 and 1.1 or 1.1 to 2.0.
Petr Onderka
@Jason, I don't think that's true. This post from Eric Gunnerson (which is, I think, where I read about this for the first time) states that the decision was made long before C# 1.0.