У меня возникли проблемы с получением компилятора для устранения правильной перегрузки для метода расширения. Лучший способ объяснить мне небольшой код. Вот сценарий LINQPad, который демонстрирует проблему. Это не будет компилироваться из-за этой проблемы у меня:Устранение перегрузки по методу Weird расширения
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();
}
}
Это компилирует и дает ожидаемые результаты:
Бар (А: IMarker)
Foo (А: IMarker)
Foo (А: IMarker)
Foo (А: IMarker)
Бар (Контейнер < >)
Foo (Container < >)
Foo (Container < >)
кажется, только есть проблема, когда я не ссылаться на параметр лямбда в лямбда-выражения, а затем только с Container<T>
класс. При вызове Bar
нет лямбды, и он отлично работает. При вызове Foo
с возвращаемым значением, основанным на параметре лямбда, он работает нормально. Даже если возвращаемое значение лямбда совпадает с значением в примере, который не компилируется, но параметр лямбда ссылается на фиктивное назначение, он работает.
Почему это работает в этих случаях, но не в первом? Я что-то делаю неправильно, или я нашел ошибку компилятора? Я подтвердил поведение как на C# 4, так и на C# 6.
@ManoDestra: Редактирует, потому что вам не нравится, где я размещаю свои фигурные скобки, не приветствуются. –
Это C#. Следовательно, редактирование. – ManoDestra
Я не вижу твоей точки. –