Sla*_*uma 7 .net c# linq overloading overload-resolution
如果我有一个类型的变量,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);
Run Code Online (Sandbox Code Playgroud)
(最后两个因为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);
Run Code Online (Sandbox Code Playgroud)
如果我在使用任何一个时遇到相同的编程错误,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
}
}
}
Run Code Online (Sandbox Code Playgroud)
"Squiggles"在编译器中看起来也不同:
我理解前两个错误.但是为什么编译器显然想要Func<T, int, bool> predicate
在最后两个示例中使用重载号4(带有)并且没有告诉我"类"没有在类中定义Test
而且"bla"和"blabla"不存在在目前的背景下?
我原本以为编译器可以安全地排除5号过载(我没有传入string
as参数)和2号和4号重载(我没有传入带有两个参数的lambda表达式(t,i) => ...
)但是我的期望不是似乎是正确的.
作为旁注:我在看这个问题时遇到了这个问题.提问者说,问题中的第四个查询没有编译(它在上面的例子3和4中确实存在编译器错误),但是这个查询正好是他的问题的解决方案,对我来说似乎是某个东西(一个变量)或者属性名称?)在查询中写错(虽然他没有确认)但是这个编译器错误没有给出有用的指示什么是错误的.
编辑
请参阅下面的Martin Harris非常有用的评论:
在示例中query4
,当我将鼠标悬停在波浪线上时,错误" Delegate System.Func不接受1参数 "是工具提示窗口中显示的错误.在编译器输出窗口中,实际上有四个错误:
但是为什么编译器没有抱怨前两个使用的例子的第一个错误IQueryable<T>
?
请阅读到最后。
实际上,这是因为您的代码存在编译时错误。
编译器通过查看您的代码来检测正确的扩展方法。在这种情况下,它应该接受一个Test
参数并返回bool
参数。由于无法编译您的 linq 表达式,因此无法检测到正确的扩展方法,并且编译器假定它找到的第一个扩展方法是您想要的扩展方法。
顺便说一句,如果您修复错误,例如
var query3 = objectQuery.Where(t => t.Id == 1)
Run Code Online (Sandbox Code Playgroud)
编译器将使用
public static IQueryable<T> Where<T>(
this IQueryable<T> source,
Expression<Func<T, bool>> predicate
);
Run Code Online (Sandbox Code Playgroud)
现在您应该想知道为什么它会跳过 Enumerable 上的方法。这是因为ObjectQuery<T>
类直接实现了'IQueryable',但实现IEnumerable<T>
是因为IQueryable<T>
.
你可以看到下面的对象层次结构