Мой вопрос мотивирован Eric Lippert's this blog post. Рассмотрим следующий код:Неоднозначность в выводе типа параметра для выражений лямбда C#
using System;
class Program {
class A {}
class B {}
static void M(A x, B y) { Console.WriteLine("M(A, B)"); }
static void Call(Action<A> f) { f(new A()); }
static void Call(Action<B> f) { f(new B()); }
static void Main() { Call(x => Call(y => M(x, y))); }
}
компилируется успешно и печатает M(A, B)
, потому что компилятор выясняет, что типы x
и y
в лямбда-выражений должны быть A
и B
соответственно. Теперь добавьте перегрузку для Program.M
:
using System;
class Program {
class A {}
class B {}
static void M(A x, B y) { Console.WriteLine("M(A, B)"); }
static void M(B x, A y) { Console.WriteLine("M(B, A)"); } // added line
static void Call(Action<A> f) { f(new A()); }
static void Call(Action<B> f) { f(new B()); }
static void Main() { Call(x => Call(y => M(x, y))); }
}
Это приводит к ошибке во время компиляции:
error CS0121: The call is ambiguous between the following methods or properties: 'Program.Call(Action<Program.A>)' and 'Program.Call(Action<Program.B>)'
компилятор не может вывести типы x
и y
. Может быть, что x
имеет тип A
и y
имеет тип B
или наоборот, и ни одна из них не может быть предпочтительной из-за полной симметрии. Все идет нормально. Теперь добавьте еще один перегрузки для Program.M
:
using System;
class Program {
class A {}
class B {}
static void M(A x, B y) { Console.WriteLine("M(A, B)"); }
static void M(B x, A y) { Console.WriteLine("M(B, A)"); }
static void M(B x, B y) { Console.WriteLine("M(B, B)"); } // added line
static void Call(Action<A> f) { f(new A()); }
static void Call(Action<B> f) { f(new B()); }
static void Main() { Call(x => Call(y => M(x, y))); }
}
компилируется успешно и печатает M(A, B)
снова! Я могу угадать причину. Компилятор разрешает перегрузку Program.Call
, пытаясь скомпилировать лямбда-выражение x => Call(y => M(x, y))
для x
типа A
и для x
типа B
. Первый успешно, в то время как последний терпит неудачу из-за неоднозначности, обнаруженной при попытке вывести тип y
. Поэтому компилятор заключает, что x
должен иметь тип A
.
Таким образом, , добавление нескольких двусмысленных результатов в меньшей двусмысленности. Это странно. Кроме того, это не согласуется с тем, что Эрик писал в вышеупомянутом посте:
If it has more than one solution then compilation fails with an ambiguity error.
Есть ли хорошая причина для текущего поведения? Это просто вопрос облегчения жизни компилятора? Или это скорее недостаток компилятора/спецификации?
Причина в том, что возвращаемый тип метода не является частью его подписи. Таким образом, при разрешении правильной перегрузки компилятор только смотрит на параметр метода. –
@viveknuna Все методы возвращают 'void', каков тип возвращаемого результата? – Kyle