5

Consider this code:

 A a = null;
 a.f(); //Will it throw NullReferenceException?

Will the above throw NullReferenceException?

The answer is : it depends on what f() is.

This difference leads to a question: how each type of method is implemeneted and viewed by C# compilers? Also, why member method must throw exception even if it doesn't access any member data? It seems that C# compiler makes an assumption in advance that member method will access member data, and so it throws exception if the object is null, as using null object member data cannot be accessed. However, in case of extension method, it postpones this decision till it actually attempts to access member data using null reference, only then it throws exception.

How far my understanding is correct? And if that is so, why this difference?

Yes, I know that if f() is an extension method, then a.f() is equivalent to writing AExt.f(a), so the latter shouldn't throw exception until a is used to access member. But my focus is mostly on the compiler implementations (which can implement even member methods in the same way).

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Extension methods are just synonyms, like you said. – bevacqua Sep 03 '11 at 19:42
  • As Nico said, it's just syntactic sugar for normal static method invocations. One example where this is convenient: it makes it possible to define a `.IsNullOrEmpty` method on string, allowing `s.IsNullOrEmpty()`. – Kirk Woll Sep 03 '11 at 19:46
  • @Kirk: Is `s.IsNullOrEmpty()` correct? Should it not be `string.IsNullOrEmpty(s)`? I think what you've written wouldn't even compile! – Nawaz Sep 03 '11 at 19:51
  • @Nawaz, it will, if you define your own extension method `IsNullOrEmpty(this string s)`. – svick Sep 03 '11 at 19:53
  • @svick: And that is my question. Why it should be work, and why not when its a member method? – Nawaz Sep 03 '11 at 19:55
  • @Nawaz while it *looks* like an instance method, it is *implemented* as a static method. (just look at the generated IL -- it's as if the concept of extension methods doesn't even exist) "dot" notation for instance members requires the actual instance for the member to have any meaning. It is nonsense for an instance method to be invoked without a valid "this" reference. The same is not true at all for a static method with a null first argument. Extension method syntax overloads the meaning of "dot" notation to also allow ad-hoc static methods to be associated with the type. – Kirk Woll Sep 03 '11 at 20:48

2 Answers2

2

Yes, this is how this code behaves (if the extension method doesn't check for null and throws an exception by itself). You're right that calling non-virtual instance method on null could work, if that method doesn't access any instance fields of the class (directly or indirectly).

But the language designers felt this would be confusing, so they make sure that the object is not null by using the callvirt IL instruction.

With extension methods, this is not as confusing (nobody expects this to be null, but an argument declared this IEnumerable<TSource> source should be checked). And you can call extension method as normal static method, so it should check for null anyway. Also, both ways of calling the function should probably behave exactly the same.

svick
  • 236,525
  • 50
  • 385
  • 514
  • I really wish the designers had defined an attribute to say "this method should be callable with null `this`, and will do something sensible"; such a design would have allowed immutable class types which encapsulate values to behave like value types [e.g. so one could say `myString.IsNullOrEmpty` rather than `String.IsNullOrEmpty(myString)`]. – supercat Dec 06 '13 at 20:29
  • @supercat Why? You can easily write that as an extension method. – svick Dec 06 '13 at 20:57
  • Extension methods have weird scoping rules and, especially from a Reflection perspective, effectively exist in a separate universe from instance methods. If there had been a way to declare an extension method *within a class*, that would have helped, but AFAIK that's not allowed: extension methods have to go in a non-nested non-generic static class, so any type or type member which is used by an extension method must be visible at that level, whether or not the method would publicly expose any details of the type or member (or even its existence). – supercat Dec 06 '13 at 21:17
1

The instance methods must throw the NullReferenceException when the object is null, because they inherently guarantee that the object is available when that method is executed. Think of the instance methods as an action that the object instance performs and when the object itself is not existent, then the action could not even be invoked. The extension methods are just syntactic sugar and the compiler immediately translates them as you mentioned above AExt.f(a). This is just a convenience and serves as an eye candy to help read the code better.

For the cases where you would want to call a method regardless of whether the instance is available or not, the language provides static methods as the feature. As you can tell, the extension methods are static methods.

Charles Prakash Dasari
  • 4,964
  • 1
  • 27
  • 46