Esta é uma pergunta sobre os métodos de extensão do C # e sua filosofia de design, então acho que a melhor maneira de responder a essa pergunta é citar Documentação do MSDN sobre o propósito dos métodos de extensão :
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.
Para resumir, os métodos de extensão são projetados para adicionar métodos de instância a um tipo específico, mesmo quando os desenvolvedores não podem fazê-lo diretamente. E como os métodos de instância substituirão sempre os métodos de extensão se presentes (se chamado usando a sintaxe do método da instância), isso deve ser somente se você não puder adicionar diretamente um método ou estender a classe . *
Em outras palavras, um método de extensão deve agir exatamente como um método de instância faria, porque pode acabar sendo feito um método de instância por algum cliente. E como um método de instância deve lançar se o objeto que está sendo chamado for null
, o mesmo acontecerá com o método de extensão.
* Como uma nota lateral, esta é exatamente a situação que os projetistas do LINQ enfrentaram: quando o C # 3.0 foi lançado, já havia milhões de clientes usando System.Collections.IEnumerable
e System.Collections.Generic.IEnumerable<T>
, tanto em suas coleções quanto em foreach
loops. Essas classes retornaram IEnumerator
objetos que tinham apenas os dois métodos Current
e MoveNext
, portanto, incluir quaisquer métodos de instância adicionais obrigatórios, como Count
, Any
etc., estaria quebrando esses milhões de clientes. Assim, para fornecer essa funcionalidade (especialmente porque ela pode ser implementada em termos de Current
e MoveNext
com relativa facilidade), eles a lançaram como métodos de extensão, que podem ser aplicados a qualquer instância IEnumerable
e também pode ser implementado por classes de maneiras mais eficientes. Se os designers do C # tivessem decidido lançar o LINQ no primeiro dia, ele teria sido fornecido como métodos de instância de IEnumerable
e provavelmente teriam projetado algum tipo de sistema para fornecer implementações de interface padrão desses métodos.