remarks example cref c# linq lambda expression func

example - remarks c#



Asignando un Func a una Expresión y viceversa (3)

En cuanto a la especificación del lenguaje C # una expresión lambda como

i => i + i

es una función anónima Una expresión con esta clasificación se puede convertir implícitamente en un tipo de delegado compatible o tipo de árbol de expresión. Es por eso que puedes escribir ambos

Func<int, int> sumFunc = i => i + i; Expression<Func<int, int>> sumExp = i => i + i;

El primero es un tipo de delegado, el segundo es un tipo de árbol de expresión. Como no existe una conversión implícita entre esos tipos, no puede asignar sumFunc = sumExp o viceversa. Pero dado que el árbol de expresiones sumExp representa una expresión lambda, puede compilar esa expresión en un delegado ejecutable y asignarlo a sumFunc , porque este es un delegado compatible:

sumFunc = sumExp.Compile();

La otra dirección no es posible, porque un delegado no se puede "descompilar" fácilmente en un árbol de expresiones.

La razón por la que no puedes escribir

object o = i => i + i;

es decir, que una función anónima no tiene un valor o tipo, y por sí misma, es simplemente convertible a un delegado o tipo de árbol de expresiones. Tienes que decirle al compilador cuál de los dos quieres, así que puedes convertirlo primero y luego asignar el resultado a una variable de tipo object :

object sumFuncObject = (Func<int, int>) (i => i + i); object sumExpObject = (Expression<Func<int, int>>) (i => i + i);

En relación con su última pregunta: puede crear conversiones implícitas o explícitas personalizadas entre tipos complejos, de modo que esta "magia" se pueda aplicar a las asignaciones. Consulte la Guía de programación de operaciones de conversión para obtener más información.

Estaba manipulando expresiones y me confundí en algunos puntos

  1. Podemos asignar el mismo LamdaExpression tanto a Expression como a Func. Pero no podemos asignar un Func a una Expresión (o una Expresión a Func). ¿Por qué no podemos hacer eso? Busqué si un operador de conversión entre Expression y Func está definido pero no pude encontrar ninguno.

    Func<int, int> sumFunc = i => i + i; Expression<Func<int, int>> sumExp = i => i + i; // sumExp = sumFunc; // Cannot convert source type ''System.Func<int,int>'' to target type ''System.Linq.Expressions.Expression<System.Func<int,int>>'' // sumFunc = sumExp; // Cannot convert source type ''System.Linq.Expressions.Expression<System.Func<int,int>>'' to target type ''System.Func<int,int>''

  2. Incluso no podemos asignar una LambdaExpression a un objeto. De nuevo, ¿por qué no podemos hacer eso?

    // object o = i => i + i; // Cannot convert source type ''lambda expression'' to target type ''object''

  3. Creo que hay algo sobre el compilador. Si es así, ¿podemos escribir nuestros tipos personalizados que se comportan de esta manera (confusa) y aprovechar algo?


Una expresión es una abstracción. Permite a Linq construir de forma eficiente consultas SQL para bases de datos, XML o para otra fuente de datos. Es similar en concepto a un árbol de sintaxis abstracto, almacena los elementos sintácticos de la consulta para que el proveedor de Linq pueda generar una consulta.

Si funcionó como esperabas, lo que tendría que hacer es tomar el árbol de sintaxis abstracta de la función lambda y generar un árbol de objetos de expresión. Bueno, eso no es posible, por lo que sé, ¿y de qué serviría?


En realidad, ambas expresiones son sintaxis azúcar, transformadas por el compilador en diferentes construcciones de lenguaje.

Cuando escribes la expresión lambda, el compilador hace esto: hace que la función miembro coincida con tu expresión lamda y la asigna a tu variable sumFunc (esto no es código exacto, solo para tener una idea):

class Program { private static int generatedname(int i) { return i + i; } static void Main() { Func<int, int> sumFunc = generatedname; } }

Cuando escribes el árbol Expresión, ocurre aún más magia. En tiempo de compilación, el compilador transforma su expresión en el árbol de expresiones "construcción". Me gusta esto.

class Program { static void Main() { var addPrm = Expression.Parameter(typeof(int), "i"); Expression<Func<int, int>> sumExp = Expression.Lambda<Func<int, int>>( Expression.Add( addPrm, addPrm ), addPrm ); } }

Ves que esto es completamente diferente, es por eso que no puedes simplemente unirte el uno al otro.