【问题标题】:Calling Task<T> methods generically一般调用 Task<T> 方法
【发布时间】:2023-03-13 06:55:01
【问题描述】:

Casting TResult in Task<TResult> to System.Object 相关。我正在为服务构建一个通用的异步命令执行功能。

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

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

代码使用反射在具有给定cmdName 的类上查找方法。调用它会返回一个Type&lt;T&gt;——我们事先并不知道T。但是由于Task&lt;T&gt; 不是协变的,我不能转换为Task&lt;object&gt;

目前我的解决方案(按照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); });

我担心这样做会否定 async 的价值:获取结果现在是一个阻塞调用,所以我还不如使用同步方法。

【问题讨论】:

  • 为什么不在 ContinueWith 调用中运行反射代码?您可能需要在 ContinueWith 之后调用 unwrap 以获取 Task
  • T 是否与 cmdName 一对一?
  • @fsimonazzi 不确定你的意思。
  • @KavehShahbazian 不,返回类型变化很大。

标签: c# generics async-await task


【解决方案1】:

请记住,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;
}

特别是,我不建议使用Task.Run,因为那样会浪费线程,我也不建议使用Task.Result,因为它会将任何异常封装在AggregateException 中。

【讨论】:

  • 感谢您的指点。 Task.Run 是当时我能想到的强制类型的唯一方法。我通过转换结果稍微调整了它,所以它仍然返回对象:return (object)(await task);
  • @Quango:考虑将返回类型更改为Task&lt;dynamic&gt;。它可以简化您的调用代码。
【解决方案2】:

您可以等待任务,然后在完成后反思结果

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

或者:

return ((dynamic)t).Result;

【讨论】:

  • 当你知道怎么做时很简单——我显然不知道!非常感谢@Lee
猜你喜欢
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多