以泛型方式调用 Task<T> 方法

4

将Task<TResult>中的TResult转换为System.Object相关。我正在为一个服务构建一个通用的异步命令执行函数。

执行通用命令的方法如下:

public async Task<object> ExecuteCommandAsync(string cmdName, CommandData data)

代码使用反射在类中查找具有给定cmdName的方法。调用此方法将返回一个>,我们无法提前知道T的类型。但是,由于Task不是协变的,所以我无法转换为Task。
目前,我的解决方案(根据21805564)是调用Result方法,并封装在Task.Run中,如下所示:
// find the method
MethodInfo cmd = GetMethod(cmdName);
var task = (Task)cmd.Invoke(this, data);
return await Task.Run<object>(() => { return task.GetType().GetProperty("Result").GetValue(task); });

我的担忧是这样做会抵消异步的价值:获取结果现在成了阻塞调用,所以我可能也可以使用同步方法。


为什么不在ContinueWith调用中运行反射代码?您可能需要在ContinueWith之后调用unwrap以获取Task<object>。 - fsimonazzi
T 是否与 cmdName 一一对应? - Kaveh Shahbazian
@fsimonazzi 不确定你的意思是什么。 - Quango
@KavehShahbazian 不,返回类型各不相同。 - Quango
2个回答

5

您可以等待任务完成后再反思结果。

public static async Task<object> AwaitResult(Task t)
{
    await t;
    return t.GetType().GetProperty("Result").GetValue(t, null);
} 

或者:

return ((dynamic)t).Result;

1
简单易懂,只要你知道怎么做——而我显然不知道!非常感谢@Lee。 - Quango

5

请记住,dynamic 是可用的。只要您不使用 Microsoft.Bcl.Async,您可以像这样做:

public async Task<dynamic> ExecuteCommandAsync(string cmdName, CommandData data)
{
  MethodInfo cmd = GetMethod(cmdName);
  dynamic task = cmd.Invoke(this, data);
  return await task;
}

特别是在IT技术中,我不建议使用Task.Run,因为这会浪费一个线程;也不建议使用Task.Result,因为它会将任何异常封装在AggregateException中。


感谢提供指针。当时我只能想到使用Task.Run来强制转换类型。我稍微调整了一下,通过对结果进行强制转换,所以它仍然返回对象:return (object)(await task); - Quango
@Quango:考虑将返回类型更改为Task<dynamic>。这可能会简化您的调用代码。 - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接