Хорошо, учитывая, что я сегодня нахожусь в процессе изложения текста, у меня будет свой удар. Я должен отметить, что я не эксперт по компилятору C #, я не читал спецификацию (любую из них ... ни для чего), и хотя эта статья, на которую вы ссылались, была действительно интересной, я бы соврал, если бы сказал в этом тоже был какой-то эксперт (или даже все понял на 100%).
Предостерегаю, мой вопрос на ваш вопрос таков:
Есть ли способ обобщить
определения типов здесь?
Я думаю, что короткий ответ - нет. С предоставленной информацией просто недостаточно информации для части вывода типа компилятора C #, чтобы вывести достаточно информации из использования различных переменных.
Как показывают другие ответы, это можно упростить. Вы можете использовать @ Lee IdentityFunc
, чтобы разрешить вывод типа с var identity
. Однако даже с этим дополнением все еще невозможно с вашим примером кода вывести все переменные типа Compose
.
Представьте себе следующую ситуацию:
public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
return x => f(g(x));
}
public static T Identity<T> (this T value)
{
return value;
}
public static Func<T, T> IdentityFunc<T>(this T value)
{
return (Func<T, T>)Identity;
}
и
public static void Run()
{
var a = 3; // a is int
var i = a.IdentityFunc(); // i is Func<int, int>;
var test = i.Compose(n => n)(a) // test is expected to be int
}
Первоначально это может выглядеть так, как будто test
должно быть легко выведено на int
. Однако тип возвращаемого значения i.Compose
может быть определен только после факта, из его использования. Компилятор C #, очевидно, не допустит этого.
public static void Run()
{
var a = 3; // a is int
var i = a.IdentityFunc(); // i is Func<int, int>;
var c = i.Compose(n => n) // c is Func<T, int> - T cannot be resolved without knowledge of n
var test = c(a); // ideally have type inference infer c (Func<T, int>) as Func<int, int>
}
В этом примере при использовании c
с a
компилятору придется ретроспективно выводить тип возврата вызова i.Compose<T, U, V>(n => n)
, равный Func<int, int>
. Это явно невозможно в компиляторе C #. Уберите вызов c(a)
, и компилятор не будет знать об использовании c
, что исключит любую возможность сделать вывод T
(но это не так). Вполне возможно, что более продвинутая система вывода типов сможет сделать вывод такого типа на основе использования обобщенного возврата (возможно, F # - еще одна тема, в которой я не разбираюсь).
Поскольку Уэс Дайер не дает конкретного использования этого конкретного примера, неизвестно, использует ли он какую-то другую магию, чтобы учесть степень вывода типов, которую вы пытаетесь достичь.
Более квалифицированные люди, такие как Эрик Липперт , смогут предоставить вам гораздо более высокий уровень детализации (а также техническую точность / остроту). Я прочитал отличный ответ, который он написал здесь, на вопрос о выводе типов, но я не могу его найти. Его блог содержит много полезной информации. Вы можете попробовать связаться с ним, если вам интересно. Кроме того, в его ответе на этот вопрос обсуждаются монады (и, в конечном счете, ссылки на статью Уэса Дайера). Возможно, вам будет интересно прочесть ее: Монада на простом английском? (Для программиста ООП без фона FP)