Me encontré con esto hoy
Una función anónima o un grupo de métodos no se puede utilizar como valor constituyente de una operación enlazada dinámicamente.
al tratar de hacer
static R ifNotNull<R>(dynamic o, Func<dynamic, R> returnFunc, R otherwise) { return ReferenceEquals(null, o) ? otherwise : returnFunc(o); }y usarlo con
dynamic firstAddress = ...; return ifNotNull<string>(firstAddress, (a) => a.address_1, null)Ahora, la mayoría de las limitaciones en la dinámica tienen sentido para mí: no puede usar un método de extensión porque ¿cómo se supone que el compilador decide en qué estático compilarlo? Pero no entiendo esto aquí. ¿De dónde viene la confusión? ¿Cuál es exactamente la limitación?
¿Cuál es el tipo estático de la lamba a => a.address_1 ? Puede sentirse tentado a decir que es un Func<dynamic, dynamic> . Pero recuerda:
Una expresión lambda es una función anónima que puede usar para crear delegados o tipos de árboles de expresión.
Así que tal vez sea una Expression<Func<dynamic, dynamic>> . Un lamda por sí mismo no tiene un solo tipo estático.
Ahora, normalmente, la inferencia de tipo se daría cuenta de que está pasando la lamba a una función que toma un Func y se convertirá en un delegado en el momento de la compilación. Sin embargo, cuando llama con argumentos dinámicos, la llamada al método se envía dinámicamente .
Si tiene una llamada de método con un argumento dinámico, se envía dinámicamente, punto. Durante el enlace en tiempo de ejecución, se conocen todos los tipos estáticos de sus argumentos (énfasis mío) y los tipos se seleccionan para los argumentos dinámicos en función de sus valores reales.
Entonces, el hecho de que su método tome un Func no se tiene en cuenta, ya que la llamada al método real no se determina hasta el tiempo de ejecución , por lo que no hay inferencia de tipo.
Para compilar esto, tendrá que convertir su lamba en un Func<dynamic, string> como se muestra a continuación:
return ifNotNull<string>(firstAddress, new Func<dynamic, string>((a) => a.address_1), null);Ahora se conoce el tipo estático de su lamda.
Quise decir que necesita convertir el método lambda en la expresión esperada que desea. Entonces funcionará bien.
Me gusta esto:
return ifNotNull(firstAddress, (Func<dynamic, string>)((a) => a.address_1), null);