Esta é uma pergunta sobre os métodos de extensão do C # e sua filosofia de design. Portanto, acho que a melhor maneira de responder a essa pergunta é citar a documentação do MSDN com a finalidade dos métodos de extensão :
Os métodos de extensão permitem "adicionar" métodos a tipos existentes sem criar um novo tipo derivado, recompilar ou modificar o tipo original. Os métodos de extensão são um tipo especial de método estático, mas são chamados como se fossem métodos de instância no tipo estendido. Para o código do cliente escrito em C #, F # e Visual Basic, não há diferença aparente entre chamar um método de extensão e os métodos realmente definidos em um tipo.
...
Em geral, recomendamos que você implemente métodos de extensão com moderação e somente quando for necessário. Sempre que possível, o código do cliente que deve estender um tipo existente deve fazê-lo criando um novo tipo derivado do tipo existente. Para mais informações, consulte Herança.
Ao usar um método de extensão para estender um tipo cujo código-fonte não pode ser alterado, você corre o risco de que uma alteração na implementação do tipo faça com que seu método de extensão seja interrompido.
Se você implementar métodos de extensão para um determinado tipo, lembre-se dos seguintes pontos:
- Um método de extensão nunca será chamado se tiver a mesma assinatura que um método definido no tipo.
- Os métodos de extensão são colocados no escopo no nível do espaço para nome. Por exemplo, se você tiver várias classes estáticas que contenham métodos de extensão em um único namespace nomeado
Extensions
, todas elas serão colocadas no escopo pela using Extensions;
diretiva.
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 sempre substituem os métodos de extensão, se presentes (se chamados usando a sintaxe do método de instância), isso só deve ser feito 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 como um método de instância, porque pode acabar sendo um método de instância por algum cliente. E como um método de instância deve ser lançado se o objeto no qual está sendo chamado for null
, o método de extensão também deve ser.
* Como observação lateral, esta é exatamente a situação que os designers do LINQ enfrentaram: quando o C # 3.0 foi lançado, já havia milhões de clientes que estavam usando System.Collections.IEnumerable
e System.Collections.Generic.IEnumerable<T>
, tanto em suas coleções quanto em foreach
loops. Essas classes retornou IEnumerator
objetos que só tinham os dois métodos Current
e MoveNext
, por isso, a adição de quaisquer métodos de instância necessárias adicionais, como Count
, Any
, etc., seria quebrar esses milhões de clientes. Portanto, 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 atualmente existenteIEnumerable
instância e também pode ser implementado por classes de maneiras mais eficientes. Se os designers do C # decidissem liberar o LINQ no primeiro dia, ele seria fornecido como método de instância IEnumerable
e provavelmente projetariam algum tipo de sistema para fornecer implementações de interface padrão desses métodos.