c# - 为方法修饰构建表达式树?

标签 c# expression-trees dynamic-invoke

我正在构建一个名为 CommandHandler 的类有 ExecuteCommand具有 Command 的方法作为输入参数。

想法是ExcecuteCommand将检查命令名称并按名称模式执行正确的类方法,因此当命令名称为 Test 时类应该有对应的TestHandler方法。

在初始化时,我使用反射来查找所有方法并在命令名称和创建的 Func<Command, Task<object>> 之间创建映射.现在我已经通过让所有方法返回 Task<object> 来实现这一点。并使用 Delegate.CreateDelegate创建Func<Command, Task<object>>来自反射方法,但我想清理代码并允许方法返回简单类型,如 int 或 Task<custom class> .

我想构建一些简单的表达式,对于简单类型将执行方法并执行 Task.FromResult动态地使类方法保持干净。对于具有特定类型结果的任务,我想创建结果为 Task<object> 的表达式所以都可以缓存为 Dictionary<string, Func<Command, Task<object>> .

 public class CommandHandler
    {
        public Dictionary<string, Func<Command, Task<object>>> methodCache = new Dictionary<string, Func<Command, Task<object>>>();

        public int IntCommandHandler(Command c)
        {
            return 5;
        }

        public string StringCommandHandler(Command c)
        {
            return "5";
        }

        public Task<int> AsyncIntCommandHandler(Command c)
        {
            return Task.Run(() => 5);
        }

        public async Task<object> OldWayCommandHandler(Command c)
        {
            return "5";
        }

        private void RegisterAsyncQueryHandlers(Dictionary<string, MethodInfo> handlers)
        {
            var filtered = handlers.Where(h => h.Value.ReturnType == typeof(Task<object>)).ToList();
            foreach (var handler in filtered)
            {
                methodCache.Add(handler.Key, (Func<Command, Task<object>>)Delegate.CreateDelegate(typeof(Func<Command, Task<object>>), this, handler.Value, false));
            }
        }

        public void FillCache()
        {
            // Get all methods with proper pattern and pass it to RegisterAsyncQueryHandlers in dictionary of command name and MethodInfo
            //RegisterAsyncQueryHandlers
        }

        public Task<object> ExecuteCommand(Command c)
        {
            return methodCache[c.Name].Invoke(c);
        }
    }

    public class Command
    {
        public string Name { get; set; }
    }

我没有使用表达式的经验,我发现的大多数示例都使用基本运算符和静态方法。也许有人可以帮助我如何构建这样的表达式?

最佳答案

如果我没理解错的话,问题是如何转换Task<TResult>Task<object> .

例如可以使用 Task<TResult>.ContinueWith 来完成方法如下:

static Task<object> Convert<TResult>(Task<TResult> source)
{
    return source.ContinueWith(t => (object)t.Result);
}

可以动态构建这样的表达式,但更容易的方法是将上述方法放在您的类中并通过以下 Expression.Call 来“调用”它过载。

构建表达式并从中编译委托(delegate)的方法可能是这样的:

Func<Command, Task<object>> MakeFunc(MethodInfo handler)
{
    var c = Expression.Parameter(typeof(Command), "c");
    var task = Expression.Call(Expression.Constant(this), handler, c);
    if (task.Type != typeof(Task<object>))
        task = Expression.Call(GetType(), "Convert", new[] { task.Type.GetGenericArguments().Single() }, task);
    var expr = Expression.Lambda<Func<Command, Task<object>>>(task, c);
    return expr.Compile();
}

关于c# - 为方法修饰构建表达式树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49716744/

相关文章:

c# - Nancy 模型绑定(bind)在 Chrome、IE 中不起作用

c# - 在设置中构建时无法访问 App.config

c# - 编译的 C# lambda 表达式性能与叠层

c# - __DynamicallyInvokable 属性有什么用?

c# - 如何将对象数组作为单独的参数传递给方法?

c# - 如何使用带有参数的 CreateProcessAsUser 是日语?

c# - 禁用 ASP.net TreeView 复选框

c# - 获取 Linq To 对象查询的字符串表示形式

ruby - 在 Ruby 中漂亮地打印树数据结构

java - 为动态调用方法生成调用层次结构