为方法修饰构建表达式树?
Build expression tree for method decoration?
我正在构建一个名为 CommandHandler
的 class,它具有 ExecuteCommand
方法,其中 Command
作为输入参数。
想法是 ExcecuteCommand
将检查命令名称并通过名称模式执行正确的 class 方法,因此当命令名称为 Test
时 class 应该有相应的 TestHandler
方法。
在初始化时,我使用反射来查找所有方法并在命令名称和创建的命令名称之间创建映射 Func<Command, Task<object>>
。现在我已经通过制作所有方法 return Task<object>
并使用 Delegate.CreateDelegate
从反射方法创建 Func<Command, Task<object>>
来实现这一点,但我想清理代码并允许方法 return 简单类型,如 int 或 Task<custom class>
。
我想构建一些简单的表达式,对于简单类型将执行方法并动态地执行 Task.FromResult
,因此 class 方法保持干净。对于具有特定类型结果的任务,我想创建结果为 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
重载将上述方法放在 class 和 "call" 中。
构建表达式并从中编译委托的方法可能是这样的:
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();
}
我正在构建一个名为 CommandHandler
的 class,它具有 ExecuteCommand
方法,其中 Command
作为输入参数。
想法是 ExcecuteCommand
将检查命令名称并通过名称模式执行正确的 class 方法,因此当命令名称为 Test
时 class 应该有相应的 TestHandler
方法。
在初始化时,我使用反射来查找所有方法并在命令名称和创建的命令名称之间创建映射 Func<Command, Task<object>>
。现在我已经通过制作所有方法 return Task<object>
并使用 Delegate.CreateDelegate
从反射方法创建 Func<Command, Task<object>>
来实现这一点,但我想清理代码并允许方法 return 简单类型,如 int 或 Task<custom class>
。
我想构建一些简单的表达式,对于简单类型将执行方法并动态地执行 Task.FromResult
,因此 class 方法保持干净。对于具有特定类型结果的任务,我想创建结果为 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
重载将上述方法放在 class 和 "call" 中。
构建表达式并从中编译委托的方法可能是这样的:
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();
}