c# - Inferencia de métodos no funciona con el grupo de métodos
.net-4.0 type-inference (2)
Considerar
void Main()
{
var list = new[] {"1", "2", "3"};
list.Sum(GetValue); //error CS0121
list.Sum(s => GetValue(s)); //works !
}
double GetValue(string s)
{
double val;
double.TryParse(s, out val);
return val;
}
La descripción para el error CS0121 es
La llamada es ambigua entre los siguientes métodos o propiedades:
''System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal>)''
and''System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal?>
) ''
Lo que no entiendo es qué información s => GetValue(s)
da al compilador que simplemente GetValue
no lo hace, ¿no es el último azúcar sintáctico para el primero?
La respuesta de Mark es correcta, pero podría necesitar un poco más de explicación.
El problema se debe a una diferencia sutil entre cómo se manejan los grupos de métodos y cómo se manejan las lambdas.
Específicamente, la diferencia sutil es que un grupo de métodos se considera convertible a un tipo de delegado únicamente sobre la base de si los argumentos coinciden, no también sobre la base de si el tipo de retorno coincide. Lambdas comprueba tanto los argumentos como el tipo de retorno.
El motivo de esta extraña regla es que las conversiones de grupos de métodos a delegados son esencialmente una solución del problema de resolución de sobrecarga . Supongamos que D es el tipo de delegado double D(string s)
y M es un grupo de métodos que contiene un método que toma una cadena y devuelve una cadena. Al resolver el significado de una conversión de M a D, hacemos una resolución de sobrecarga como si dijeras M (cadena). La resolución de sobrecarga seleccionaría la M que toma una cadena y devuelve una cadena, por lo que M es convertible a ese tipo de delegado , aunque la conversión resulte en un error más adelante . Del mismo modo que la resolución de sobrecarga "normal" tendría éxito si dijera "cadena s = M (nulo);" - la resolución de sobrecarga es exitosa, aunque eso cause un error de conversión más tarde.
Esta regla es sutil y un poco rara. El resultado de esto aquí es que su grupo de métodos es convertible a todos los diferentes tipos de delegados que son los segundos argumentos de cada versión de Sum que toma un delegado . Dado que no se puede encontrar la mejor conversión, la resolución de sobrecarga en el grupo de métodos Sum
es ambigua.
Las reglas de conversión de grupos de métodos son plausibles, pero un poco extrañas en C #. Estoy un poco molesto de que no sean consistentes con las conversiones lambda más "intuitivamente correctas".
s => GetValue(s)
es una expresión lambda y GetValue
es un grupo de métodos, que es una cosa completamente diferente. Ambos pueden considerarse azúcar sintáctica para la new Func<string,double>(...)
pero la única forma en que se relacionan entre sí es que la expresión lambda incluye una llamada a GetValue()
. Cuando se trata de convertir a un delegado, los grupos de métodos tienen diferentes reglas de conversión que las expresiones lambda con respecto a los tipos de retorno. Consulte ¿Por qué es funcional <T> ambiguo con Func <IEnumerable <T>>? y ¿El argumento del grupo de métodos sobrecargado confunde la resolución de sobrecarga? .