コンパイラが拡張メソッドの正しいオーバーロードを解決するのに問題があります。私が説明する最善の方法は、少しのコードです。この問題を示すLINQPadスクリプトがあります。私が手奇妙な拡張メソッドオーバーロードの解決
void Main(){
new Container<A>().Foo(a=>false);
}
interface IMarker{}
class A : IMarker{
public int AProp{get;set;}
}
class B : IMarker{
public int BProp{get;set;}
}
class Container<T>{}
static class Extensions{
public static void Foo<T>(this T t, Func<T, bool> func)
where T : IMarker{
string.Format("Foo({0}:IMarker)", typeof(T).Name).Dump();
}
public static void Foo<T>(this Container<T> t, Func<T, bool> func){
string.Format("Foo(Container<{0}>)", typeof(T).Name).Dump();
}
}
あり、エラーがある:
呼び出しは次のメソッドやプロパティの間であいまいです:「
Extensions.Foo<Container<A>>(Container<A>, System.Func<Container<A>,bool>)
」と 'Extensions.Foo<A>(Container<A>, System.Func<A,bool>)
これは、私がいる問題でコンパイルされません'
まったくあいまいではないようです。最初の方法はContainer<T>
を受け入れず、IMarker
のみを受け取ります。これは、一般的な制約がオーバーロードの解決を支援していないように思えるが、コードのこのバージョンでは、彼らがあるように見えるん:
void Main(){
new A().Bar();
new A().Foo(a=>a.AProp == 0);
new A().Foo(a=>false); // even this works
new A().Foo(a=>{
var x = a.AProp + 1;
return false;
});
new Container<A>().Bar();
new Container<A>().Foo(a=>a.AProp == 0);
new Container<A>().Foo(a=>{
var x = a.AProp + 1;
return false;
});
}
interface IMarker{}
class A : IMarker{
public int AProp{get;set;}
}
class B : IMarker{
public int BProp{get;set;}
}
class Container<T>{}
static class Extensions{
public static void Foo<T>(this T t, Func<T, bool> func)
where T : IMarker{
string.Format("Foo({0}:IMarker)", typeof(T).Name).Dump();
}
public static void Foo<T>(this Container<T> t, Func<T, bool> func){
string.Format("Foo(Container<{0}>)", typeof(T).Name).Dump();
}
public static void Bar<T>(this T t) where T : IMarker{
string.Format("Bar({0}:IMarker)", typeof(T).Name).Dump();
}
public static void Bar<T>(this Container<T> t){
string.Format("Bar(Container<{0}>)", typeof(T).Name).Dump();
}
}
これは、コンパイルし、期待される結果が得られます。
バー(A:IMarker)
フー(A:IMarker)
フー(A:IMarker)
フー(A:IMarker)
バー(コンテナ< >)
はFoo(コンテナ< >)
はFoo(コンテナ< >)
それだけContainer<T>
で、私はラムダ式でラムダパラメータを参照しない場合にのみ、問題を持っているようだ、とクラス。 Bar
を呼び出すと、ラムダはなく、正常に動作します。ラムダパラメータに基づいて戻り値を持つFoo
を呼び出すと、正常に動作します。ラムダの戻り値が、たとえコンパイルされないがラムダパラメータが仮割り当てによって参照されているものと同じであっても、それは機能します。
なぜこれらのケースでは動作しますが、最初のケースでは機能しませんか?間違ったことをやっているのですか、あるいはコンパイラのバグを見つけましたか?私はC#4とC#6の両方の動作を確認しました。
@ManoDestra:私は中括弧を置くのが好きではないので、編集は歓迎されません。 –
これはC#です。したがって編集。 – ManoDestra
私はあなたの意見を見ていません。 –