使用Lambda表达式调用通用方法(以及仅在运行时已知的类型)

时间:2010-05-17 15:15:00

标签: c# generics lambda expression expression-trees

您可以使用Lambda Expression Objects将lambda表示为表达式。

如果在运行时只知道用于泛型方法签名的类型,如何创建表示泛型方法调用的Lambda Expression Object

例如:

我想创建一个Lambda Expression Objects来调用: public static TSource Last<TSource>( this IEnumerable<TSource> source )

但我只知道TSource在运行时是什么。

2 个答案:

答案 0 :(得分:26)

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)
}

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)
}

答案 1 :(得分:2)

我不完全理解这个问题,但是dtb编写的代码可以简单地写成:

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

dtb中的示例中的代码与C#编译器从此lambda表达式自动生成的内容(编译为表达式树,因为返回类型为Expression)几乎相同。

如果您在运行时知道类型,那么您可以使用dtb的解决方案,也可以使用Reflection调用CreateLambda方法(上面),这可能比较慢,但允许您编写代码自然C#中的lambda:

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

这种方法的好处是CreateLambda中的代码可能要复杂得多,而使用表达式树很难明确。