这个答案是对 Andras Zoltan 答案的一种评论(但这太长了,不适合评论格式)。
Zoltan 的回答很有趣,而且大部分都是正确的,除了C# 将 lambda 视为Expression<>
首要的 [...]。
Expression<>
C# 将 lambda(和任何匿名函数)视为与委托和同一委托的(表达式树)同样“接近” 。根据 C# 规范,两者都不是“更好的转换目标”。
所以考虑这段代码:
class C
{
public void Overloaded(Expression<Func<int, int>> e)
{
Console.WriteLine("expression tree");
}
public void Overloaded(Func<int, int> d)
{
Console.WriteLine("delegate");
}
}
然后:
var c = new C();
c.Overloaded(i => i + 1); // will not compile! "The call is ambiguous ..."
所以它起作用的原因IQueryable<>
是另外一回事。直接接口类型定义的方法优于基接口中定义的方法。
为了说明,将上面的代码更改为:
interface IBase
{
void Overloaded(Expression<Func<int, int>> e);
}
interface IDerived : IBase
{
void Overloaded(Func<int, int> d);
}
class C : IDerived
{
public void Overloaded(Expression<Func<int, int>> e)
{
Console.WriteLine("expression tree");
}
public void Overloaded(Func<int, int> d)
{
Console.WriteLine("delegate");
}
}
然后:
IDerived x = new C();
x.Overloaded(i => i + 1); // compiles! At runtime, writes "delegate" to the console
如您所见,IDerived
选择的是 中定义的成员,而不是 中定义的成员IBase
。请注意,我颠倒了这种情况(与 相比IQueryable<>
),因此在我的示例中,委托重载是在最派生的接口中定义的,因此优于表达式树重载。
注意:在这种IQueryable<>
情况下,所OrderBy
讨论的方法不是普通的实例方法。相反,一种是派生接口的扩展方法,另一种是基接口的扩展方法。但解释是相似的。