Extension Methods Resolution
Extension methods resolution is one of the most important concepts to understand if you want to master LINQ. Consider the following code. In it, we define a custom list of type Customer, called Customers, and a class, CustomersEnumerable, that provides an extension method, called Where, which applies specifically to instances of the Customers type:
If we use our usual customers array, the behavior of the query in Listing 4-56 is quite interesting.
Listing 4-56: A query expression over a custom list of type Customers
Customers customersList = new Customers(customers);
var expr =
from c in customersList
where c.City == "Brescia"
select c;
foreach (var item in expr) {
Console.WriteLine(item);
}
The query expression will be converted by the compiler into the following code, as we saw early in this chapter:
As a result of the presence of the CustomersEnumerable class, the extension method Where will be the one defined by CustomersEnumerable, instead of the general-purpose one defined in System.Linq.Enumerable. (To be considered as an extension method container class, the CustomersSequence class must be in the current namespace or in any namespace included in active using directives.) Now we are experiencing the real power of LINQ. Using extension methods, we are able to define custom behaviors for specific types. In the following chapters, we will discuss LINQ to SQL, LINQ to XML, and other implementations of LINQ. These implementations are just specific implementations of query operators, thanks to the extension methods resolution realized by the compilers.
At this time, everything looks fine, and it is, of course! By the way, imagine that you need to query the custom list of type Customers with the standard Where extension method rather than with the specialized one. You should convert the custom list to a more generalized one to divert the extension method resolution made by the compiler. This is another scenario that can benefit from conversion operators.