Questa è una domanda sui metodi di estensione di C # e sulla loro filosofia di progettazione, quindi penso che il modo migliore per rispondere a questa domanda sia citare La documentazione di MSDN ai fini dei metodi di estensione :
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.
Per riassumere, i metodi di estensione sono progettati per aggiungere metodi di istanza a un tipo particolare, anche quando gli sviluppatori non possono farlo direttamente. E poiché i metodi di istanza sempre sovrascrivono i metodi di estensione se presenti (se chiamati usando la sintassi del metodo di istanza), questo dovrebbe solo essere eseguito se non è possibile aggiungere direttamente un metodo o estendere la classe . *
In altre parole, un metodo di estensione dovrebbe agire proprio come farebbe un metodo di istanza, poiché potrebbe finire per essere reso un metodo di istanza da qualche client. E perché un metodo di istanza dovrebbe essere lanciato se l'oggetto su cui è chiamato è null
, quindi dovrebbe essere il metodo di estensione.
* Come nota a margine, questa è esattamente la situazione che i progettisti di LINQ hanno affrontato: quando è stato rilasciato C # 3.0, c'erano già milioni di client che utilizzavano System.Collections.IEnumerable
e System.Collections.Generic.IEnumerable<T>
, sia nelle loro raccolte che in foreach
cicli. Queste classi hanno restituito IEnumerator
oggetti che avevano solo i due metodi Current
e MoveNext
, quindi l'aggiunta di eventuali ulteriori metodi di istanza richiesti, come Count
, Any
, ecc., Infrangerebbe questi milioni di client. Quindi, per fornire questa funzionalità (soprattutto perché può essere implementata in termini di Current
e MoveNext
con relativa facilità), l'hanno rilasciato come metodi di estensione, che possono essere applicati a qualsiasi istanza IEnumerable
esistente esistente e può anche essere implementato dalle classi in modi più efficienti. Se i progettisti di C # decidessero di rilasciare LINQ il primo giorno, sarebbero stati forniti come metodi di esempio di IEnumerable
e probabilmente avrebbero progettato un qualche tipo di sistema per fornire implementazioni di interfaccia predefinite di tali metodi.