Also remember that extension methods were added as a way to help Linq query to be more readable, when used in their C# style.
These 2 affectations are absolutely equivalent, yet the first is far more readable (and the gap in readibility would of course increase with more methods chained).
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));
Note that the fully qualified syntax should even be :
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));
By chance, the type parameters of Where
and Last
don't need to be explicitely mentioned as they can be infered thanks to the presence of the first parameter of these two methods (the parameter which is introduced by the keyword this
and make them extension methods).
This point is obviously an advantage (among others) of the extension methods, and you can take benefit from it in every similar scenario where method chaining is involved.
Especially, it is the more elegant and convincing way I found to have a base class method invokable by any subclass and returning a strongly typed reference to this subclass (with the subclass type).
Example (ok, this scenario is totally cheesy) : after a good night, an animal opens the eyes then gives a cry; every animal opens the eyes the same way, whereas a dog barks and a duck kwaks.
public abstract class Animal
{
//some code common to all animals
}
public static class AnimalExtension
{
public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
{
//Some code to flutter one's eyelashes and then open wide
return animal; //returning a self reference to allow method chaining
}
}
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(); //*1
Donald.OpenTheEyes().Kwak(); //*2
}
}
Conceptually OpenTheEyes
should be an Animal
method, but it would then return an instance of the abstract class Animal
, which doesn't know specific subclass methods like Bark
or Duck
or whatever. The 2 lines commented as *1 and *2 would then raise a compile error.
But thanks to the extension methods, we can have kind of a "base method which knows the subclass type on which it is called".
Note that a simple generic method could have done the job, but in a far more awkward way :
public abstract class Animal
{
//some code common to all animals
public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
{
//Some code to flutter one's eyelashes and then open wide
return (TAnimal)this; //returning a self reference to allow method chaining
}
}
This time, no parameter and thus no possible return type inference. The call can be nothing other than :
Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();
... which can weigh the code a lot if more chaining is involved (especially knowing that the type parameter will always be <Dog>
on Goofy's line and <Duck>
on Donald's one...)
Extensions.To(1, 10)
is meaningless and1.To(10)
is descriptive. Of course I understand the technical side you're talking about, just saying. In fact there are scenarios where one "couldn't have" used extension approach in place of static methods, reflection for instance, another case isdynamic
. – Essence