c# - 创建 lambda 表达式以调用泛型类中的方法

标签 c# c#-4.0 lambda expression-trees func

我有这些简单的界面:

public interface IQuery<TResult> { }

public interface IQueryHandler<in TQuery, out TResult> 
    where TQuery : IQuery<TResult> {
    TResult Handle(TQuery query);
}

并且有一些它们的实现。我正在尝试创建一个表达式树来调用 Handle指定处理程序上的方法。我的意思是:

var query = new MyQuery(); // which MyQuery implements IQuery<int>
object handler = _someServiceProvider
    .Get<IQueryHandler<MyQuery, int>>();

此外,还有一个MyQueryHandler :

public class MyQueryHandler : IQueryHandler<MyQuery, int> {
    public int Handle(MyQuery query) { return 20; }
}

现在,我正在尝试创建一个 Func<object, MyQuery, int>像这样调用:

var func = GetMethod<MyQuery, int>(handler);
var result = func(handler, query);

这是我的GetMethod实现:

    private Func<object, TQuery, TResult> GetMethod<TQuery, TResult>(object obj)
        where TQuery : IQuery<TResult> {

        var methodInfo = obj.GetType().GetMethod(nameof(IQueryHandler<TQuery, TResult>.Handle));

        var insExp = Expression.Parameter(typeof(object), "ins");

        var inputExp = Expression.Parameter(typeof(TQuery), "query");

        var instanceExp = Expression.Variable(obj.GetType(), "instance");

        var assExp = Expression.Assign(instanceExp, Expression.Convert(insExp, obj.GetType()));

        var castExp = Expression.Convert(inputExp, methodInfo.GetParameters()[0].ParameterType);

        var callExp = Expression.Call(instanceExp, methodInfo, castExp);

        var blockExp = Expression.Block(new Expression[] {
            insExp,
            inputExp,
            instanceExp,
            assExp,
            castExp,
            callExp
        });

        var func =
            Expression.Lambda<Func<object, TQuery, TResult>>(
                blockExp,
                insExp,
                inputExp).Compile();
        return func;
    }

但是,当我尝试编译 Lambda 时,我收到此错误:

An exception of type 'System.InvalidOperationException' occurred in System.Core.dll but was not handled in user code

Additional information: variable 'instance' of type 'Namespace.MyQueryHandler' referenced from scope '', but it is not defined

我哪里错了?我错过了什么?你有什么主意吗?提前致谢。

最佳答案

据我所知,您正在尝试编写此函数:

TResult f(object ins, TQuery query)
{
    var instance = (MyQueryHandler)ins;
    return instance.Handle(query);
}

要使用表达式树执行此操作,您必须在 Expression.Block 中声明变量,但随后仅指定上面的两个语句,而不是所有子表达式:

var blockExp = Expression.Block(new[] { instanceExp }, new Expression[] {
    assExp,
    callExp
});

但更简单的选择是编写以下函数:

TResult f(object ins, TQuery query)
{
    return ((MyQueryHandler)ins).Handle(query);
}

看起来像这样:

var callExp = Expression.Call(
    Expression.Convert(insExp, obj.GetType()), methodInfo, castExp);

var func =
    Expression.Lambda<Func<object, TQuery, TResult>>(
        callExp,
        insExp,
        inputExp).Compile();

关于c# - 创建 lambda 表达式以调用泛型类中的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44098384/

相关文章:

c# - 单向绑定(bind)

c# - 自定义SynchronizationContext在unittest中异步设置Thread.CurrentPrincipal

sql-server-2008 - 更新阿拉伯语数据

java lambda :How to count total items in a list?

java - 通过 Java-8 中的公共(public)字段减少对象集合

c# - 获取枚举的最大值

c# - Windows 服务 canStop 属性

c# - 枚举集合的不同方法

c# - 如何在 C# 中获取对象(类、结构)的大小

带或的 Python Lambda