如何方法重载的工作(LINQ凡扩展方法)? [英] How does method overload resolution work (LINQ Where extension method)?

查看:229
本文介绍了如何方法重载的工作(LINQ凡扩展方法)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有类型的变量的IQueryable< T> 我有四个扩展方法其中,的命名空间 Systm.Linq 可供选择:

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

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);

(最后两个,因为的IQueryable&LT; T&GT; 继承了IEnumerable&LT; T&GT;

如果我用类型的变量的ObjectQuery&LT; T&GT; (在命名空间 System.Data.Objects )我有五个重载其中,可用,即上述的四(因为的ObjectQuery&LT; T&GT; 工具 IQueryable的&LT; T&GT; 的IEnumerable&LT; T&GT; 其它接口之间),另外这个类的一个实例方法:

If I use a variable of type ObjectQuery<T> (in namespace System.Data.Objects) I have five overloads of Where available, namely the four above (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);

如果我在使用做同样的程序错误或者的IQueryable&LT; T&GT; 的ObjectQuery&LT; T&GT; 我得到非常不同的编译器错误。下面是一个例子程序(在VS2010 SP1 +标准的C#控制台应用程序模板 System.Data.Entity.dll 组件添加到项目引用中,编译器错误是在四个下面的评论例子):

If I do the same programming mistake while using either 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 references, the compiler error is in comment below the 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 as well in the compiler:

据我所知,前两个错误。但为什么编译器显然要使用过载4号(与 Func键&LT; T,INT,BOOL&GT; predicate ),在过去的两个例子,并没有按'牛逼告诉我,名是不是类定义的测试和喇嘛和布拉布拉不要在当前情况下是否存在?

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

我所预料的编译器可以安全地排除过载5号(我不传入字符串作为参数)和过载2号和4(我不'T传递一个lambda EX pression用的两个的参数(T,I)=&GT; ... ),但我的期望没有按'吨似乎是正确的。

I had expected that the compiler can safely rule out overload number 5 (I don't pass in a string as parameter) and overload number 2 and 4 (I don't pass in a lambda expression with two parameters (t,i) => ...) but my expectation doesn't seem to be correct.

作为一个方面说明:我碰到这个问题,当在看<一href="http://stackoverflow.com/questions/11729384/returning-a-collection-of-objects-where-an-objects-property-matches-any-property">this问题。提问者说,在问题的第四查询不编译(它恰在实施例序号3和4上面的编译器错误),但这个查询是完全解决其问题,我似乎某物(可变或属性名称?)写入错误的查询(他没有证实这一点虽然),但这个编译器错误,不给一个有用的提示什么是错的。

As a side note: I came across this problem when looking at this question. The questioner said there that the fourth query in the question does not compile (it has exactly the compiler error in example number 3 and 4 above), but this query is exactly the solution to his problem and to me it seems that something (a variable or property name?) is written wrong in the query (he didn't confirm this though) but this compiler error doesn't give a helpful indication what is wrong.

修改

。参见下面的马丁·哈里斯非常有帮助的注释:

Refering to Martin Harris' very helpful comment below:

在例如 query4 错误的代表System.Func用不了1参数的是,当我将鼠标悬停提示窗口中显示的错误在胡乱写的字线。在编译器输出窗口实际上有四个错误顺序如下:

In example query4 the error "Delegate System.Func does not take 1 argument" is the error shown in the tooltip window when I hover over the squiggle line. In the compiler output window there are actually four errors in this order:

  • 代表System.Func用不了1参数
  • 拉姆达EX pression不能转换为字符串,因为串不是委托类型
  • 命名为喇嘛并不在当前的背景下存在
  • 名为布拉布拉并不在当前上下文中存在
  • Delegate System.Func does not take 1 argument
  • "lambda expression" cannot be converted to "string" because "string" is not a delegate type
  • The name "bla" does not exist in the current context
  • The name "blabla" does not exist in the current context

但是,为什么不编译器抱怨的第一个错误的使用的IQueryable&LT前两个例子; T&GT;

But why doesn't the compiler complain with the first error for the first two examples that use IQueryable<T>?

推荐答案

请阅读,直到结束。

其实这是因为你的code的编译时错误。

Actually it is because your code has compiler time errors.

编译器通过看你的code检测正确的扩展方法。在这种情况下,应该采取测试参数和返回值布尔参数。由于您的LINQ EX pression不能编译,正确的扩展方法不能检测出来,编译器假定它发现第一个扩展方法是你想要的人。

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

顺便说一句,如果你喜欢固定

BTW, if you fix error like

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
);

现在你应该知道为什么它会跳过方法上枚举。这是因为的ObjectQuery&LT; T&GT; 类直接实现IQueryable的性,但的IEnumerable&LT; T&GT; ,因为的IQueryable&LT; T&GT;

Now you should wonder why it skips method on Enumerable. It is because ObjectQuery<T> class directly implements 'IQueryable', but implements IEnumerable<T> because of IQueryable<T>.

您可以看到下面
对象层次

you can see object hierarchy below

这篇关于如何方法重载的工作(LINQ凡扩展方法)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆