Я играл с проектом хобби, когда сталкивался с ошибкой типа-вывода, которую я не понимал. Я упростил его на следующий тривиальный пример.
У меня есть следующие классы и функции:
class Foo { }
class Bar { }
class Baz { }
static T2 F<T1, T2>(Func<T1, T2> f) { return default(T2); }
static T3 G<T1, T2, T3>(Func<T1, Func<T2, T3>> f) { return default(T3); }
Теперь рассмотрим следующие примеры:
// 1. F with explicit type arguments - Fine
F<Foo, Bar>(x => new Bar());
// 2. F with implicit type arguments - Also fine, compiler infers <Foo, Bar>
F((Foo x) => new Bar());
// 3. G with explicit type arguments - Still fine...
G<Foo, Bar, Baz>(x => y => new Baz());
// 4. G with implicit type arguments - Bang!
// Compiler error: Type arguments cannot be inferred from usage
G((Foo x) => (Bar y) => new Baz());
Последний пример создает ошибку компилятора, но мне кажется, что он должен иметь возможность выводить аргументы типа без каких-либо проблем.
ВОПРОС: Почему компилятор не может указать <Foo, Bar, Baz>
в этом случае?
ОБНОВЛЕНИЕ: Я обнаружил, что простое перенос второго лямбда в функцию идентификации заставит компилятор правильно выводить все типы:
static Func<T1, T2> I<T1, T2>(Func<T1, T2> f) { return f; }
// Infers G<Foo, Bar, Baz> and I<Bar, Baz>
G((Foo x) => I((Bar y) => new Baz()));
Почему он может делать все отдельные шаги совершенно, но не весь вывод сразу? Есть ли какая-то тонкость в том порядке, в котором компилятор анализирует неявные типы лямбда и неявные общие типы?