C#编译器如何区分Where方法的Func与Expression两种重载?
Where Method for IQueryable<T> Great question! Let's walk through exactly how the compiler decides which Where overload to use in your code.
First, let's recap the context you provided:
list.AsQueryable()returns an instance ofIQueryable<int>IQueryable<int>inherits fromIEnumerable<int>, and declares its ownWhere(Expression<Func<int, bool>>)methodIEnumerable<int>defines theWhere(Func<int, bool>)method
Here's the step-by-step breakdown of the compiler's decision process:
1. Collect all candidate Where methods
When you call .Where(x => x > 0) on an IQueryable<int> instance, the compiler first gathers every available method named Where that could apply. This includes:
- The
Where(Expression<Func<int, bool>>)method directly declared onIQueryable<int> - The
Where(Func<int, bool>)method inherited fromIEnumerable<int>
2. Filter for "feasible" methods
Next, the compiler checks which of these methods can actually accept your argument (x => x > 0). A lambda expression like this can be implicitly converted to two different types:
Func<int, bool>: A delegate that represents executable codeExpression<Func<int, bool>>: An expression tree that represents the structure of the code (not the code itself)
Since both conversions are valid, both Where methods are considered feasible candidates.
3. Select the best match
This is where the compiler's overload resolution rules kick in. The key factors here are:
- Prefer methods declared directly on the target type: The
Where(Expression<...>)method is part ofIQueryable<int>itself, while the other is inherited from a base interface. The compiler prioritizes methods defined directly on the type you're calling against. - Align with the type's design intent:
IQueryable<T>is built to work with expression trees (so queries can be translated to SQL, LINQ to Entities, etc.). The compiler recognizes this design goal and leans toward the overload that fits the type's purpose.
Proof of this behavior
You can force the compiler to pick the other overload by explicitly converting the lambda to the desired type:
// Forces the use of IEnumerable<int>.Where(Func<int, bool>) var positives = list.AsQueryable().Where((Func<int, bool>)(x => x > 0)); // Forces the use of IQueryable<int>.Where(Expression<Func<int, bool>>) var positives = list.AsQueryable().Where((Expression<Func<int, bool>>)(x => x > 0));
内容的提问来源于stack exchange,提问作者Spiff

