この回答は、Andras Zoltan の回答に対する一種のコメントです (ただし、これは長すぎてコメント形式に収まりません)。
Zoltan の答えは興味深いものであり、C# がラムダを何よりも重要な [...] と見なすExpression<>
というフレーズを除いて、ほとんど正しいです。
Expression<>
C# は、ラムダ (および任意の無名関数) をデリゲートおよびその同じデリゲートの (式ツリー) に等しく "近い" と見なします。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
メソッドが通常のインスタンス メソッドではない場合。代わりに、1 つは派生インターフェイスの拡張メソッドであり、もう 1 つは基本インターフェイスの拡張メソッドです。しかし、説明は似ています。