gpt4 book ai didi

c# - 方法重载解析如何工作(LINQ Where 扩展方法)?

转载 作者:太空狗 更新时间:2023-10-29 20:31:20 26 4
gpt4 key购买 nike

如果我有一个 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> 以及其他接口(interface)),另外还有这个类的一个实例方法:

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

“Squiggles”在编译器中看起来也不同:

enter image description here

我理解前两个错误。但是,为什么编译器显然要在最后两个示例中使用重载编号 4(使用 Func<T, int, bool> predicate )并且不告诉我“名称”未在类 Test 中定义?并且“bla”和“blabla”在当前上下文中不存在?

我原以为编译器可以安全地排除 5 号重载(我没有传入 string 作为参数)和 2 号和 4 号重载(我没有传入带有 的 lambda 表达式两个 参数 (t,i) => ... ) 但我的期望似乎不正确。

附带说明:我在查看 this question 时遇到了这个问题.发问者在那里说问题中的第四个查询没有编译(它在上面的示例 3 和 4 中确实有编译器错误),但是这个查询正是他的问题的解决方案,对我来说似乎有些东西(一个变量或属性名称?)在查询中写错了(虽然他没有确认这一点)但是这个编译器错误并没有给出一个有用的指示是什么出了问题。

编辑

引用下面 Martin Harris 非常有用的评论:

例如query4错误“Delegate System.Func does not take 1 argument”是当我将鼠标悬停在波浪线上时工具提示窗口中显示的错误。在编译器输出窗口中实际上有四个错误顺序:

  • Delegate System.Func 不接受 1 个参数
  • “lambda 表达式”无法转换为“字符串”,因为“字符串”不是委托(delegate)类型
  • 名称“bla”在当前上下文中不存在
  • 名称“blabla”在当前上下文中不存在

但为什么编译器不为前两个使用 IQueryable<T> 的示例提示第一个错误? ?

最佳答案

请阅读到最后。

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

编译器通过查看您的代码来检测正确的扩展方法。在这种情况下,它应该采用 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
);

现在您应该想知道为什么它会跳过 Enumerable 上的方法。是因为ObjectQuery<T>类直接实现“IQueryable”,但实现IEnumerable<T>因为IQueryable<T> .

你可以看到下面的对象层次结构
object hierarchy

关于c# - 方法重载解析如何工作(LINQ Where 扩展方法)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11738417/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com