简体   繁体   English

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

[英]Build expression tree for method decoration?

I'm building a class named CommandHandler that have ExecuteCommand method that have Command as input parameter. 我正在构建一个名为CommandHandler的类,它具有ExecuteCommand方法,该方法具有Command作为输入参数。

The Idea is that ExcecuteCommand will check command name and execute proper class method by the name pattern so when command name is Test class should have corresponding TestHandler method. 想法是, ExcecuteCommand将检查命令名称并通过名称模式执行正确的类方法,因此当命令名称为Test类时,应具有相应的TestHandler方法。

On initialization I'm using reflection to find all methods and create a mapping between command name and created Func<Command, Task<object>> . 在初始化时,我使用反射来查找所有方法,并在命令名称和创建的Func<Command, Task<object>>之间创建映射。 For now I have achieve this by making all methods return Task<object> and use Delegate.CreateDelegate to create Func<Command, Task<object>> from reflected method but I would like to clean code and allow methods to return simple types like int or Task<custom class> . 现在我已经通过使所有方法返回Task<object>并使用Delegate.CreateDelegate从反射方法创建Func<Command, Task<object>>来实现这一点,但我想清理代码并允许方法返回像int这样的简单类型或Task<custom class>

I would like to build some simple Expression that for simple types will execute method and do Task.FromResult dynamically so class method remains clean. 我想构建一些简单的表达式,对于简单类型将执行方法并动态执行Task.FromResult因此类方法保持干净。 For Task with specific type result I would like to create expression that will result Task<object> so all could be cached as Dictionary<string, Func<Command, Task<object>> . 对于具有特定类型结果的任务,我想创建将导致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; }
    }

I have no experience with using Expressions and most of the samples I found are using basic operators and static methods. 我没有使用表达式的经验,我发现的大多数样本都使用基本运算符和静态方法。 Maybe someone can help me ho w to build such expression? 也许有人可以帮助我建立这样的表达?

If I understand correctly, the question is how to convert Task<TResult> to Task<object> . 如果我理解正确,问题是如何将Task<TResult>转换为Task<object>

It can be done for instance using the Task<TResult>.ContinueWith method as follows: 例如,可以使用Task<TResult>.ContinueWith方法完成,如下所示:

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

It's possible to dynamically build such expression, but the easier would be to put the above method in your class and "call" it via the following Expression.Call overload. 可以动态构建这样的表达式,但更容易将上面的方法放在你的类中,并通过下面的Expression.Call重载“调用”它。

The method that builds expression and compiles a delegate from it could be like this: 构建表达式并从中编译委托的方法可能如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM