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

Posted

技术标签:

【中文标题】使用 Lambda 表达式调用通用方法(以及仅在运行时知道的类型)【英文标题】:Calling a Generic Method using Lambda Expressions (and a Type only known at runtime) 【发布时间】:2011-02-20 11:19:19 【问题描述】:

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

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

例如:

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

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

【问题讨论】:

这并不完全清楚。您要在哪个对象上创建哪种方法?你想用 lambda 表达式引用 Last 泛型方法吗? @CasperOne:嗨,Casper! a) 我正在尝试创建一个引用 TheMethodTheObject 实例。 b) 是的,我想用 lambda 表达式(我的意思是 lambda 表达式对象)引用最后一个方法。谢谢:) 【参考方案1】:
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)

【讨论】:

【参考方案2】:

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

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

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

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

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

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

【讨论】:

嗨,托马斯!我需要提高我知道的编程沟通技巧,我知道哈哈哈(但别担心我正在努力:)。我更新了问题以代表我的真正意思。不错的重构! +1 @SDReyes:“在运行时”是重点。不过,您仍然可以为此使用漂亮的 C# 语法(无需显式构造表达式树)。请参阅我的更新答案。 嗨,托马斯!,我同意你的看法。这种方法让您可以在 CreateLambda 方法中轻松实现复杂的 lambda(只需权衡性能)。这次我将使用 dtb 方法,因为我们已经在我们正在处理的组件中使用了很多表达式,并且我想保持代码之间的连贯性:)。但我也很乐意在接下来的场景中实现你的!干得好托马斯!问候。标清

以上是关于使用 Lambda 表达式调用通用方法(以及仅在运行时知道的类型)的主要内容,如果未能解决你的问题,请参考以下文章

C++中函数参数以及Lambda 函数与表达式

std::function()函数std::bind()函数以及lambda

Lambda 表达式以及如何组合它们?

Lambda表达式和通用方法

Expression.Compile 与 Lambda、直接与虚拟调用的性能

Java Lambda 表达式的官网教程理解