Bueno, ya que estoy en un rollo por escupir texto esta noche voy a tener mi propia puñalada. Debo señalar que no soy un experto en el compilador de C#, no he leído las especificaciones (ninguna de ellas ... para nada), y aunque ese artículo que vinculó era realmente interesante, estaría mintiendo si dijera que era cualquier tipo de experto en eso tampoco (o incluso lo entendía todo al 100%).
Advertencias aparte, mi opinión sobre su pregunta es la siguiente:
¿Hay alguna manera de que puedo generalizar las definiciones de tipos de aquí?
Creo que la respuesta corta es no. Con la información proporcionada, simplemente no hay suficiente información para la parte de inferencia tipo del compilador de C# para inferir suficiente información del uso de las diversas variables.
Como demuestran las otras respuestas aquí, se puede simplificar. Puede usar @ Lee's IdentityFunc
para permitir la inferencia de tipo con var identity
. Sin embargo, incluso con esta adición, aún no es posible con su código de muestra inferir todas las variables de tipo Compose
.
Imagínese la siguiente situación:
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;
}
y
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
}
Inicialmente Esto podría parecer como si test
debe deducirse fácilmente a int
. Sin embargo, el tipo de devolución de i.Compose
solo se puede deducir después del hecho, a partir de su uso. El compilador de C# obviamente no permitirá esto.
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>
}
En ese ejemplo, al uso de c
con a
el compilador tendría que inferir retrospectivamente el tipo de retorno de la llamada a ser i.Compose<T, U, V>(n => n)
Func<int, int>
. Esto obviamente no es posible en el compilador de C#. Elimine la llamada c(a)
y el compilador no tendría conocimiento del uso de c
, lo que eliminaría cualquier posibilidad de inferir T
(no es que pueda hacerlo de todos modos). Es posible que un sistema de inferencia de tipo más avanzado pueda hacer este tipo de inferencia en función del uso de una declaración genérica (posiblemente F # - otro tema sobre el que no soy experto).
Como Wes Dyer no proporciona un uso específico de ese ejemplo en particular, se desconoce si hay alguna otra magia que utilice para permitir el grado de inferencia de tipo que intenta lograr.
Más personas cualificadas como Eric Lippert podrían proporcionarle un nivel de detalle mucho mayor (y precisión/agudeza técnica). Leí una excelente respuesta que escribió aquí a una pregunta sobre la inferencia de tipo, pero no puedo encontrarla. Su blog tiene mucha información excelente. Podrías intentar contactarlo si estás interesado. Además, su respuesta a esta pregunta aquí analiza las mónadas (y finalmente enlaces al artículo de Wes Dyer) compre que podría estar interesado en leerlo: Monad in plain English? (For the OOP programmer with no FP background)
¿Puede proporcionar información más específica sobre lo que está tratando de lograr? Actualmente su función Compose está muy restringida para permitir la inferencia de tipo T de una lambda. Simplemente no puede obtener suficiente información del uso. – jeffora
actualizó la pregunta. – CaptainCasey