How does method overload processing work (LINQ Where extension method)?

If I have a variable of type IQueryable<T> , I have four extension methods for Where in the Systm.Linq namespace:

 public static IQueryable<T> Where<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate); public static IQueryable<T> Where<T>(this IQueryable<T> source, Expression<Func<T, int, bool>> predicate); public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate); public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, int, bool> predicate); 

(The last two, because IQueryable<T> inherits from IEnumerable<T> .)

If I use a variable of type ObjectQuery<T> (in the System.Data.Objects namespace), I have five Where overloads, namely four of them (because ObjectQuery<T> implements IQueryable<T> and IEnumerable<T> among other interfaces) and, in addition, an instance method of this class:

 public ObjectQuery<T> Where(string predicate, params ObjectParameter[] parameters); 

If I make the same programming error when using IQueryable<T> or ObjectQuery<T> , I get very different compiler errors. Here is an example program (standard C # console application template in VS2010 SP1 + System.Data.Entity.dll assembly added to project links, compiler error in the comment below four examples):

 using System.Data.Objects; using System.Linq; namespace OverloadTest { public class Test { public int Id { get; set; } } class Program { static void Main(string[] args) { IQueryable<Test> queryable = null; ObjectQuery<Test> objectQuery = null; var query1 = queryable.Where(t => t.Name == "XYZ"); // no definition for "Name" in class OverloadTest.Test var query2 = queryable.Where(t => bla == blabla); // "bla", "blabla" do not exist in current context var query3 = objectQuery.Where(t => t.Name == "XYZ"); // Delegate System.Func<Overload.Test,int,bool> // does not take 1 argument var query4 = objectQuery.Where(t => bla == blabla); // Delegate System.Func<Overload.Test,int,bool> // does not take 1 argument } } } 

"Squiggles" look different in the compiler:

enter image description here

I understand the first two errors. But why does the compiler seem to want to use overload number 4 (with Func<T, int, bool> predicate ) in the last two examples and does not tell me that the "Name" is not defined in the Test class and that "bla" and " blabla "does not exist in the current context?

I was expecting the compiler to safely eliminate overloading number 5 (I don't pass the string as parameter) and overload number 2 and 4 (I don't pass the lambda expression with two parameters (t,i) => ... ), but my expectation is doesn't seem right.

As a side note: I ran into this problem while viewing this question . The questionnaire said there that the fourth request in the question does not compile (it has exactly the compiler error in examples 3 and 4 above), but this request is exactly the solution to its problem, and it seems to me that something (a variable or a property name? ) is spelled incorrectly in the request (he did not confirm this, though), but this compiler error does not provide a useful indication of what is wrong.

Edit

Referring to Martin Harris's wonderful comment below:

In the query4 example query4 error "Delegate System.Func does not accept 1 argument" is the error displayed in the tooltip when I hover over the cross line. There are four errors in the compiler output window in this order:

  • System.Func delegate does not accept 1 argument
  • "lambda expression" cannot be converted to "string" because "string" is not a type of delegation
  • The name "bla" does not exist in the current context
  • The name "blabla" does not exist in the current context

But why does the compiler not complain about the first error for the first two examples that use IQueryable<T> ?

+7
source share
1 answer

Read to the end.

This is actually because your code has compiler-time errors.

The compiler detects the correct extension method by looking at your code. In this case, it is assumed to take the Test parameter and return the bool parameter. Since the linq expression cannot be compiled, the correct extension method cannot be detected, and the compiler assumes the first extension method that it found is the one you need.

By the way, if you are fixing a bug, for example

 var query3 = objectQuery.Where(t => t.Id == 1) 
Compiler

will use

 public static IQueryable<T> Where<T>( this IQueryable<T> source, Expression<Func<T, bool>> predicate ); 

Now you should wonder why it skips a method in Enumerable. This is because the ObjectQuery<T> class directly implements "IQueryable", but implements IEnumerable<T> because of IQueryable<T> .

you can see the hierarchy of objects below
object hierarchy

+4
source

All Articles