Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

this == null inside .NET instance method - why is that possible?

Tags:

c#

.net

I've always thought that it's impossible for this to be null inside instance method body. Following simple program demonstrates that it is possible. Is this some documented behaviour?

class Foo {     public void Bar()     {         Debug.Assert(this == null);     } }  public static void Test() {                 var action = (Action)Delegate.CreateDelegate(typeof (Action), null, typeof(Foo).GetMethod("Bar"));     action(); } 

UPDATE

I agree with the answers saying that it's how this method is documented. However, I don't really understand this behaviour. Especially because it's not how C# is designed.

We had gotten a report from somebody (likely one of the .NET groups using C# (thought it wasn't yet named C# at that time)) who had written code that called a method on a null pointer, but they didn’t get an exception because the method didn’t access any fields (ie “this” was null, but nothing in the method used it). That method then called another method which did use the this point and threw an exception, and a bit of head-scratching ensued. After they figured it out, they sent us a note about it. We thought that being able to call a method on a null instance was a bit weird. Peter Golde did some testing to see what the perf impact was of always using callvirt, and it was small enough that we decided to make the change.

http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx

like image 608
empi Avatar asked May 16 '12 19:05

empi


People also ask

Why is this null C#?

null (C# Reference) The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables. Ordinary value types cannot be null, except for nullable value types.

Can this be null in C#?

In C#, the compiler does not allow you to assign a null value to a variable. So, C# 2.0 provides a special feature to assign a null value to a variable that is known as the Nullable type. The Nullable type allows you to assign a null value to a variable.


2 Answers

Because you're passing null into the firstArgument of Delegate.CreateDelegate

So you're calling an instance method on a null object.

http://msdn.microsoft.com/en-us/library/74x8f551.aspx

If firstArgument is a null reference and method is an instance method, the result depends on the signatures of the delegate type type and of method:

If the signature of type explicitly includes the hidden first parameter of method, the delegate is said to represent an open instance method. When the delegate is invoked, the first argument in the argument list is passed to the hidden instance parameter of method.

If the signatures of method and type match (that is, all parameter types are compatible), then the delegate is said to be closed over a null reference. Invoking the delegate is like calling an instance method on a null instance, which is not a particularly useful thing to do.

like image 175
Mark Sowul Avatar answered Sep 29 '22 16:09

Mark Sowul


Sure you can call into a method if you are using the call IL instruction or the delegate approach. You will set this booby trap only off if you try to access member fields which will give you the NullReferenceException you did seek for.

try

 int x;  public void Bar()  {         x = 1; // NullRefException         Debug.Assert(this == null);  } 

The BCL does even contain explicit this == null checks to aid debugging for languages which do not use callvirt (like C#) all the time. See this question for further infos.

The String class for example has such checks. There is nothing mysterious about them except that you will not see the need for them in languages like C#.

// Determines whether two strings match.  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]  public override bool Equals(Object obj) {     //this is necessary to guard against reverse-pinvokes and     //other callers who do not use the callvirt instruction     if (this == null)         throw new NullReferenceException();      String str = obj as String;     if (str == null)          return false;      if (Object.ReferenceEquals(this, obj))          return true;      return EqualsHelper(this, str); } 
like image 43
Alois Kraus Avatar answered Sep 29 '22 16:09

Alois Kraus