So when using EF Core and you use most of the Linq extensions you actually use
System.Linq.Expressions instead of the usual
So lets say you are using
FirstOrDefault on a
DbContext.Foos.FirstOrDefault(x=> x.Bar == true);
FirstOrDefault it will show you the following overload:
public static TSource FirstOrDefault<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
But there is also an overload for
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
When you want to store an expression in a variable you can do something like the following:
Func<Entity, bool> = x => x.Bar == true;
Expression<Func<Entity, bool>> = x => x.Bar == true;
So how does the compiler decide which overload should be used while using these extension methods?
Notice that the
Expression<Func<T,bool>> variant applies to
IQueryable<T>, whereas the
Func<T, bool> variant applies to
When looking for a matching method, the compiler will always pick the one closest to the object's type. The inheritance hierarchy is as follows:
DbSet<T> : IQueryable<T> : IEnumerable<T>
Note: there may be other inheritances inbetween, but that doesn't matter. What matters is which is closest to
IQueryable<T> is closer related to
Therefore, the compiler will try to find a matching method in
IQueryable<T>. It asks two questions:
IQueryable<T> has a
FirstOrDefault method, so bullet point 1 is satisfied); and since
x => x.MyBoolean can be implicitly converted to an
Expression<Func<T, bool>>, bullet point 2 is also satisfied.
Therefore, you end up with the
Expression<Func<T,bool>> variant defined on
x => x.MyBoolean could not be implicitly converted to
Expression<Func<T,bool>> but could be converted to
Func<T,bool> (note: this isn't the case, but this could happen for other types/values), then bullet point 2 would not have been satisfied.
At this point, since the compiler did not find a match in
IQueryable<T>, it will keep looking further, stumbling on
IEnumerable<T> and ask itself the same questions (bullet points). Both bullet points would have been satified.
Therefore, in this case, you would've ended up with the
Func<T,bool> variant defined on
Notice that even though I pass
int values (which the base method signature uses), The
double signature of the
Derived class fits (because
int implicitly converts to
double) and the compiler never looks in the
However, this isn't true in
int does not implicitly convert to
string, there is no match found in
Derived2, and the compiler looks further in
Base and uses the
int method from
The accepted answer is a reasonable explanation, but I thought I might provide a little more detail.
So lets say you are using FirstOrDefault on a DbSet.
DbContext.Foos.FirstOrDefault(x=> x.Bar == true);
First off, I hope you would not write that. If you want to ask "is it raining?" do you ask "is it raining?" or do you ask "is the statement that it is raining a true statement?" Just say
FirstOrDefault(x => x.Bar).
Next, given these overloads:
public static TSource FirstOrDefault<TSource>( this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) public static TSource FirstOrDefault<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate)
How does the compiler choose which overload is the best?
First we do type inference to determine what
TSource is in each. The details of the type inference algorithm are complex; ask a more focussed question if you have a question about it.
If type inference fails to determine a type for
TSource in either, the failed inference method is discarded from the set of candidates. In your example
TSource can be determined to be
Next, of the candidates that remain, we check them for applicability of arguments to formals. That is, can we convert every supplied argument to its corresponding formal parameter type? (And of course, is the number of arguments provided correct, and so on.) In your example both methods are applicable.
Of the applicable candidates that remain, we now enter a round of betterness checking. How does betterness checking work? Again, we do it argument-by-argument. In this case we have two questions to answer:
DbContext.Fooscan be converted to either
IQueryable<Foo>. Which, if either, is the better conversion?
The second question is easy to answer: neither is better. We learn nothing from this argument with respect to betterness.
To answer the first question, we apply the rule conversion to specific is better than conversion to general. If given a choice to convert to Giraffe or Mammal, converting to Giraffe is better. So now the question is which is more specific,
The rule of specificity checking is straightforward: if X can be implicitly converted to Y but Y cannot be implicitly converted to X, then X is the more specific. A Giraffe can be used where an Animal is needed, but an Animal cannot be used where a Giraffe is needed, so Giraffe is more specific. Or: every giraffe is an animal, but not every animal is a giraffe, so giraffe is more specific.
By this measure,
IQueryable<T> is more specific than
IEnumerable<T> because every queryable is an enumerable but not every enumerable is a queryable.
So the queryable is more specific, and therefore that conversion is better.
Now we ask the question "is there a unique applicable candidate method where compared to every other candidate, at least one conversion was better and no conversion was worse?" There is; the queryable candidate has the property that it is better in one argument than every other, and not worse in every other argument, and it is the unique method that has this property.
Therefore overload resolution chooses that method.
I encourage you to read the specification if you have more questions.