Я провел следующие тесты на вывод:
static class InferenceTest {
static void TakeInt(int a) { }
static int GiveInt() { return 0; }
static int TakeAndGiveInt(int a) { return 0; }
static void ConsumeAction1<T>(Action<T> a) { }
static void ConsumeFunc1<T>(Func<T> f) { }
static void ConsumeFunc2a<T1, T2>(Func<T1, T2> f) { }
static void ConsumeFunc2b<T>(Func<int, T> f) { }
static void ConsumeFunc2c<T>(Func<T, T> f) { }
static void ConsumeFunc1Func2<T1, T2>(Func<T1> f1, Func<T1, T2> f2) { }
static void Main() {
ConsumeAction1(TakeInt); //error
ConsumeFunc1(GiveInt); //ok
ConsumeFunc2a(TakeAndGiveInt); //error
ConsumeFunc2b(TakeAndGiveInt); //ok
ConsumeFunc2c(TakeAndGiveInt); //error
ConsumeFunc1Func2(GiveInt, TakeAndGiveInt); //ok
}
}
Результаты показывают, что компилятор С# не может вывести аргументы универсального типа для параметров функции делегата из неуниверсальной группы методов.
Больше всего меня озадачивает то, что С# может определить аргументы типа для Func<T1, T2>
из значений, возвращаемых методом в ConsumeFunc1Func2
, но не может определить типы для Func<T, T>
в ConsumeFunc2c
.
Этот вопрос похож на T Func & lt; S, T & gt; выводится из вывода лямбда-выражения, только когда S и T различаются? вопрос, но вместо лямбда-выражений с неизвестными типами параметров у нас есть неуниверсальные группы методов.
Тип Почему С# не может сделать вывод из этого, казалось бы, простого и очевидного вопроса, отвечает на вопросы "Почему не однозначных неуниверсальных методов недостаточно для вывода?" и "Почему существует разница между типами аргументов и типом возвращаемого значения для вывода?".
Вопросы:
Почему компилятор С# может определить тип Func<T>
, используя тип возвращаемого значения, но не видит успеха в случае Func<T, T>
?
Почему компилятор С# может вывести аргумент типа T1
для Func<T1, T2>
из Func<T1>
в ConsumeFunc1Func2
, но не может вывести аргумент типа T
для Func<T, T>
из самого себя в ConsumeFunc2c
, который кажется более простым?