Cómo llamar a un método genérico utilizando expresiones Lambda (y un tipo que solo se conoce en tiempo de ejecución)

c# expression expression-trees generics lambda

Pregunta

Puede utilizar los objetos de expresión Lambda para representar un lambda como una expresión.

¿Cómo se crea un objeto de expresión Lambda que representa una llamada de método genérico, si solo conoce el tipo que se utiliza para la firma del método genérico en tiempo de ejecución?

Por ejemplo:

Quiero crear un objeto de expresión Lambda para llamar: public static TSource Last<TSource>( this IEnumerable<TSource> source )

Pero solo sé qué es TSource en tiempo de ejecución.

Respuesta aceptada

static Expression<Func<IEnumerable<T>, T>> CreateLambda<T>()
{
    var source = Expression.Parameter(
        typeof(IEnumerable<T>), "source");

    var call = Expression.Call(
        typeof(Enumerable), "Last", new Type[] { typeof(T) }, source);

    return Expression.Lambda<Func<IEnumerable<T>, T>>(call, source)
}

o

static LambdaExpression CreateLambda(Type type)
{
    var source = Expression.Parameter(
        typeof(IEnumerable<>).MakeGenericType(type), "source");

    var call = Expression.Call(
        typeof(Enumerable), "Last", new Type[] { type }, source);

    return Expression.Lambda(call, source)
}

Respuesta popular

No entiendo completamente la pregunta, pero el código que escribió dtb podría escribirse simplemente como:

class MyUtils {
  public static Expression<Func<IEnumerable<T>, T>> CreateLambda<T>() { 
    return source => source.Last();
  }
}

El código en el ejemplo de dtb es casi lo mismo que lo que el compilador de C # genera automáticamente para usted a partir de esta expresión lambda (compilada como árbol de expresiones, porque el tipo de retorno es Expression ).

Si conoce el tipo en tiempo de ejecución, puede usar la solución de dtb o puede invocar el método CreateLambda (arriba) usando Reflection, que puede ser más lento, pero le permite escribir el código en lambda en el C # natural:

var createMeth = typeof(MyUtils).GetMethod("CreateLambda");
LambdaExpression l = createMeth.MakeGenericMethod(yourType).Invoke();

Lo bueno de este enfoque es que el código en CreateLambda puede ser mucho más complicado, lo que sería muy difícil de usar explícitamente con árboles de expresión.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow