Otros ya han señalado que hay infinitos tipos de delegados posibles que podría haber querido decir; lo que se trata tan especial Func
que merece ser el defecto en lugar de Predicate
o Action
, o cualquier otra posibilidad? Y, para lambdas, ¿por qué es obvio que la intención es elegir la forma delegada, en lugar de la forma del árbol de expresión?
Pero podríamos decir que Func
es especial, y que el tipo inferido de un método lambda o anónimo es Func de algo. Todavía tendríamos todo tipo de problemas. ¿Qué tipos le gustaría inferir para los siguientes casos?
var x1 = (ref int y)=>123;
No hay ningún Func<T>
tipo que tome una referencia de nada.
var x2 = y=>123;
No sabemos el tipo del parámetro formal, aunque sí sabemos el retorno. (¿O sí? ¿El retorno es int? Largo? Corto? Byte?)
var x3 = (int y)=>null;
No sabemos el tipo de devolución, pero no puede ser nulo. El tipo de retorno podría ser cualquier tipo de referencia o cualquier tipo de valor anulable.
var x4 = (int y)=>{ throw new Exception(); }
Nuevamente, no sabemos el tipo de retorno, y esta vez puede ser nulo.
var x5 = (int y)=> q += y;
¿Se pretende que sea una declaración lambda que devuelva el vacío o algo que devuelva el valor asignado a q? Ambos son legales; ¿Cuál deberíamos elegir?
Ahora, podría decir, bueno, simplemente no es compatible con ninguna de esas características. Solo admite casos "normales" donde los tipos pueden ser resueltos Eso no ayuda. ¿Cómo me facilita la vida? Si la función funciona a veces y falla a veces, aún tengo que escribir el código para detectar todas esas situaciones de falla y dar un mensaje de error significativo para cada una. Todavía tenemos que especificar todo ese comportamiento, documentarlo, escribir pruebas para ello, etc. Esta es una característica muy costosa que ahorra al usuario tal vez media docena de pulsaciones de teclas. Tenemos mejores formas de agregar valor al lenguaje que pasar mucho tiempo escribiendo casos de prueba para una función que no funciona la mitad del tiempo y que apenas proporciona ningún beneficio en los casos en que sí funciona.
La situación en la que es realmente útil es:
var xAnon = (int y)=>new { Y = y };
porque no hay un tipo "hablable" para esa cosa. Pero tenemos este problema todo el tiempo, y solo usamos la inferencia de tipo de método para deducir el tipo:
Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });
y ahora la inferencia de tipo de método determina cuál es el tipo de función.
Func<>
acepta hasta 16 argumentos.