This is a question about C#'s extension methods and their design philosophy, so I think that the best way to answer this question is to quote MSDN's documentation on the purpose of extension methods:
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C#, F# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.
…
In general, we recommend that you implement extension methods sparingly and only when you have to. Whenever possible, client code that must extend an existing type should do so by creating a new type derived from the existing type. For more information, see Inheritance.
When using an extension method to extend a type whose source code you cannot change, you run the risk that a change in the implementation of the type will cause your extension method to break.
If you do implement extension methods for a given type, remember the following points:
- An extension method will never be called if it has the same signature as a method defined in the type.
- Extension methods are brought into scope at the namespace level. For example, if you have multiple static classes that contain extension methods in a single namespace named
Extensions
, they will all be brought into scope by the using Extensions;
directive.
To summarize, extension methods are designed to add instance methods to a particular type, even when the developers cannot do so directly. And because instance methods will always override extension methods if present (if called using instance method syntax), this should only be done if you cannot directly add a method or extend the class.*
In other words, an extension method should act just like an instance method would, because it may end up being made an instance method by some client. And because an instance method should throw if the object it's being called on is null
, so should the extension method.
*As a side note, this is exactly the situation that the designers of LINQ faced: when C# 3.0 was released, there were already millions of clients that were using System.Collections.IEnumerable
and System.Collections.Generic.IEnumerable<T>
, both in their collections and in foreach
loops. These classes returned IEnumerator
objects which only had the two methods Current
and MoveNext
, so adding any additional required instance methods, such as Count
, Any
, etc., would be breaking these millions of clients. So, in order to provide this functionality (especially since it can be implemented in terms of Current
and MoveNext
with relative ease), they released it as extension methods, which can be applied to any currently existing IEnumerable
instance and can also be implemented by classes in more efficient ways. Had C#'s designers decided to release LINQ on day one, it would have been provided as instance methods of IEnumerable
, and they probably would have designed some kind of system to provide default interface implementations of those methods.
null |> Seq.isEmpty
throwsSystem.ArgumentNullException: Value cannot be null
. The expectation seems to be that you won't be passing undefined values for something that is expected to exist, so it's still an exception when you have a null. If it's a matter of initialization, I would start with an empty sequence instead of anull
.null
when dealing with collections but instead use an empty collection in those cases.Any
is just consistent.