Ricorda anche che i metodi di estensione sono stati aggiunti come un modo per aiutare le query di Linq ad essere più leggibili, se usate nel loro stile C #.
Queste 2 affettazione sono assolutamente equivalenti, ma la prima è molto più leggibile (e il divario di leggibilità aumenterebbe ovviamente con più metodi concatenati).
int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();
int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));
Tieni presente che la sintassi completa dovrebbe anche essere:
int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();
int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));
Casualmente i parametri di tipo di Wheree Lastnon necessitano di essere esplicitamente menzionati in quanto possono essere desunti grazie alla presenza del primo parametro di questi due metodi (il parametro che viene introdotto dalla parola chiavethis e li rende metodi di estensione).
Questo punto è ovviamente un vantaggio (tra gli altri) dei metodi di estensione e puoi trarne vantaggio in ogni scenario simile in cui è coinvolto il concatenamento di metodi.
In particolare, è il modo più elegante e convincente che ho trovato di avere un metodo di classe base invocabile da qualsiasi sottoclasse e che restituisce un riferimento fortemente tipizzato a questa sottoclasse (con il tipo di sottoclasse).
Esempio (ok, questo scenario è totalmente dozzinale): dopo una buona notte, un animale apre gli occhi e poi lancia un grido; ogni animale apre gli occhi allo stesso modo, mentre un cane abbaia e un'anatra kwaks.
public abstract class Animal
{
}
public static class AnimalExtension
{
public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
{
return animal;
}
}
public class Dog : Animal
{
public void Bark() { }
}
public class Duck : Animal
{
public void Kwak() { }
}
class Program
{
static void Main(string[] args)
{
Dog Goofy = new Dog();
Duck Donald = new Duck();
Goofy.OpenTheEyes().Bark();
Donald.OpenTheEyes().Kwak();
}
}
Concettualmente OpenTheEyesdovrebbe essere un Animalmetodo, ma restituirebbe un'istanza della classe astratta Animal, che non conosce metodi di sottoclasse specifici come Barko Ducko altro. Le 2 righe commentate come * 1 e * 2 avrebbero quindi generato un errore di compilazione.
Ma grazie ai metodi di estensione, possiamo avere una specie di "metodo di base che conosce il tipo di sottoclasse su cui è chiamato".
Nota che un semplice metodo generico avrebbe potuto fare il lavoro, ma in un modo molto più scomodo:
public abstract class Animal
{
public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
{
return (TAnimal)this;
}
}
Questa volta, nessun parametro e quindi nessuna possibile inferenza sul tipo restituito. La chiamata non può essere altro che:
Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();
... che può pesare molto il codice se sono coinvolti più concatenamenti (soprattutto sapendo che il parametro type sarà sempre <Dog>sulla riga di Pippo e <Duck>su quella di Donald ...)