Tengo el siguiente código:
Func<string, bool> comparer = delegate(string value) {
return value != "0";
};
Sin embargo, lo siguiente no se compila:
var comparer = delegate(string value) {
return value != "0";
};
¿Por qué el compilador no puede entender que es un Func<string, bool>
? Toma un parámetro de cadena y devuelve un valor booleano. En cambio, me da el error:
No se puede asignar un método anónimo a una variable local tipada implícitamente.
Tengo una suposición y es que si se compila la versión var , carecería de coherencia si tuviera lo siguiente:
var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
return false;
};
Lo anterior no tendría sentido ya que Func <> permite solo hasta 4 argumentos (en .NET 3.5, que es lo que estoy usando). Quizás alguien podría aclarar el problema. Gracias.
Func<>
acepta hasta 16 argumentos.Func<string, bool>
? ¡AConverter<string, bool>
mí me parece!Dim comparer = Function(value$) value <> "0"
Respuestas:
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 dePredicate
oAction
, 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?No hay ningún
Func<T>
tipo que tome una referencia de nada.No sabemos el tipo del parámetro formal, aunque sí sabemos el retorno. (¿O sí? ¿El retorno es int? Largo? Corto? Byte?)
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.
Nuevamente, no sabemos el tipo de retorno, y esta vez puede ser nulo.
¿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:
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:
y ahora la inferencia de tipo de método determina cuál es el tipo de función.
fuente
Solo Eric Lippert lo sabe con certeza, pero creo que es porque la firma del tipo delegado no determina de forma exclusiva el tipo.
Considera tu ejemplo:
Aquí hay dos posibles inferencias de lo que
var
debería ser:¿Cuál debería inferir el compilador? No hay una buena razón para elegir uno u otro. Y aunque a
Predicate<T>
es funcionalmente equivalente a aFunc<T, bool>
, todavía son tipos diferentes a nivel del sistema de tipos .NET. Por lo tanto, el compilador no puede resolver inequívocamente el tipo de delegado y debe fallar la inferencia de tipo.fuente
Eric Lippert tiene una vieja publicación al respecto donde dice
fuente
Los diferentes delegados se consideran diferentes tipos. por ejemplo,
Action
es diferente deMethodInvoker
, y una instancia deAction
no se puede asignar a una variable de tipoMethodInvoker
.Entonces, dado un delegado anónimo (o lambda) como
() => {}
, ¿es unAction
o unMethodInvoker
? El compilador no puede decirlo.Del mismo modo, si declaro que un tipo de delegado toma un
string
argumento y devuelve unbool
, ¿cómo sabría el compilador que realmente desea unFunc<string, bool>
tipo de delegado? No puede inferir el tipo de delegado.fuente
Los siguientes puntos son del MSDN con respecto a las variables locales escritas implícitamente:
Referencia de MSDN: Variables locales escritas implícitamente
Teniendo en cuenta lo siguiente con respecto a los métodos anónimos:
Referencia de MSDN: métodos anónimos
Sospecharía que, dado que el método anónimo puede tener firmas de métodos diferentes, el compilador no puede inferir correctamente cuál sería el tipo más apropiado para asignar.
fuente
Mi publicación no responde la pregunta real, pero sí responde la pregunta subyacente de:
"¿Cómo evito tener que escribir algún tipo fugoso como
Func<string, string, int, CustomInputType, bool, ReturnType>
?"[1]Siendo el programador perezoso / hacky que soy, experimenté usando
Func<dynamic, object>
, que toma un solo parámetro de entrada y devuelve un objeto.Para múltiples argumentos, puede usarlo así:
Consejo: puedes usar
Action<dynamic>
si no necesita devolver un objeto.Sí, sé que probablemente va en contra de tus principios de programación, pero esto tiene sentido para mí y probablemente para algunos codificadores de Python.
Soy bastante novato en los delegados ... solo quería compartir lo que aprendí.
[1] Esto supone que no está llamando a un método que requiere
Func
un parámetro predefinido , en cuyo caso, tendrá que escribir esa cadena fugly: /fuente
¿Qué tal eso?
fuente