如何方法重载的工作(LINQ凡扩展方法)?(How does method overload res

2019-07-30 17:19发布

如果我有类型的变量IQueryable<T>我有四个扩展方法Where在命名空间Systm.Linq可用:

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<T>从继承IEnumerable<T>

如果我使用类型的变量ObjectQuery<T>命名空间System.Data.Objects )我有五个重载Where可用时,即上述的四(因为ObjectQuery<T>实现IQueryable<T>IEnumerable<T>其他中接口),此外这个类的一个实例的方法:

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

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

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
        }
    }
}

“波浪线”看起来不同,以及在编译:

据我所知,前两个错误。 但为什么编译器显然要使用过载4号(与Func<T, int, bool> predicate在最后两个例子),并没有告诉我,“名”是不是在类中定义的Test和“喇嘛”和“布拉布拉”在目前的情况下不存在?

我所预料的是,编译器可以安全地排除过载号5(我不以通过string作为参数)和过载号2和4(I不lambda表达式通过使用两个参数(t,i) => ... ),但我的期望值似乎并不正确。

作为一个方面说明:我碰到这个问题看的时候来到了这个问题 。 提问说,在这个问题第四查询不编译(它正好在上面的例子中3号和4编译器错误),但此查询是完全解决他的问题,我似乎什么(变量或属性名称?)写入错误的查询(他没有,虽然证实了这一点),但此编译器错误不给一个有用的指示什么是错的。

编辑

指的下方马丁·哈里斯非常有帮助的评论:

在示例query4错误“ 代表System.Func不采取1个参数 ”是在提示窗口所示,当我将鼠标悬停在波浪线线的误差。 在编译器输出窗口实际上有顺序四大误区:

  • 代表System.Func用不了1个争论
  • “λ表达式”不能被转换为“串”,因为“字符串”不是委托类型
  • 命名为“喇嘛”并不在当前的背景下存在
  • 命名为“布拉布拉”并不在当前的背景下存在

但为什么不编译器的第一个错误抱怨为使用前两个例子IQueryable<T>

Answer 1:

请仔细阅读,直到结束。

其实这是因为你的代码中有编译时错误。

编译器通过看你的代码检测正确的扩展方法。 在这种情况下,它应该采取一个Test参数和返回bool参数。 由于您的LINQ表达式无法编译,正确的扩展方法不能检测到,并且编译器假定第一扩展方法才发现是你想要的人。

顺便说一句,如果你像修复错误

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

编译器将使用

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

现在你应该知道为什么它会跳过方法上枚举。 这是因为ObjectQuery<T>类直接实现'IQueryable的',但实现IEnumerable<T>由于IQueryable<T>

你可以看到下面的对象层次



文章来源: How does method overload resolution work (LINQ Where extension method)?