【问题标题】:Task with result unknown type结果未知类型的任务
【发布时间】:2015-06-28 06:25:06
【问题描述】:

我正在开发异步 CQS API

WebAPI 方法如下所示

public async Task<object> Get([FromUri] Contract contract)
{
    return  await _invoker.Invoke(CreateDto<Query>(contract));
}

不能隐式转换类型 'System.Threading.Tasks.Task&lt;System.Collections.Generic.IEnumerable&lt;Customer&gt;&gt;' 到'System.Threading.Tasks.Task&lt;object&gt;

如何在不知道类型的情况下从结果中返回任务?

这是调用通用类型类的代码

public Task<object> Invoke(Query query)
{
    var queryHandlerType = typeof(IQueryHandler<,>);
    var queryType = query.GetType();
    var queryResultType = queryType.BaseType.GetGenericArguments().First();
    var handler = _container.GetInstance(queryHandlerType.MakeGenericType(queryType, queryResultType)) as dynamic;
    return handler.Handle(query as dynamic);
}

编辑: WebApi 不支持Task&lt;T&gt; 暴露为任务有什么原因吗?如果我从任务更改为普通任务,它将不起作用。它仍然是一个任务,所以 WebApi 应该能够用一些魔法来解决这个问题?我想做这个

public Task Get([FromUri] Contract contract)
{
    return _invoker.Invoke(CreateDto<Query>(contract));
}

【问题讨论】:

  • 现在它返回一个 Task 也需要更新,请参阅调用程序代码的更新
  • 有什么理由声明它返回 Task&lt;object&gt; 而不是普通的旧 Task
  • 你不能有返回值?这样做时,WebApi 不会显示任何内容
  • 错误消息提示 _invoker.Invoke 返回 Task&lt;IEnumerable&lt;Customer&gt;&gt; 但您的 Invoke 代码返回 Task&lt;object&gt;。这种类型从何而来?等待任务后,您应该能够将结果上载到object
  • 不能将返回值转换为对象吗?抱歉,我无法在控制台中轻松复制。

标签: c# asynchronous asp.net-web-api async-await


【解决方案1】:

这个问题有点令人困惑。特别不清楚错误消息的来源。根据您发布的小代码,我认为唯一有意义的是您实际上在您的 Invoke() 方法的 return 语句中收到了该错误消息。 IE。 handler.Handle(query as dynamic) 返回一个 Task&lt;System.Collections.Generic.IEnumerable&lt;Customer&gt;&gt; 类型的对象。当然,这与Task&lt;object&gt; 不同,因此是非法的。

如果我理解正确,那么在我看来,您可以通过将 Invoke() 方法本身更改为 async 来解决该问题,这样您就可以在 Result 中重新包装最终返回的 System.Collections.Generic.IEnumerable&lt;Customer&gt; 对象Task&lt;object&gt; 而不是当前正在生成的 Task&lt;System.Collections.Generic.IEnumerable&lt;Customer&gt;&gt;

public async Task<object> Invoke(Query query)
{
    var queryHandlerType = typeof(IQueryHandler<,>);
    var queryType = query.GetType();
    var queryResultType = queryType.BaseType.GetGenericArguments().First();
    var handler = _container.GetInstance(queryHandlerType.MakeGenericType(queryType, queryResultType)) as dynamic;
    return await handler.Handle(query as dynamic);
}


如果这不能解决您的具体问题,请编辑问题以使其更清楚。请提供可靠地重现问题的a good, minimal, complete code example

【讨论】:

  • 这行得通,它实际上与 Solal Pirellis 的答案相同。像这样包裹它有什么影响?它会导致同步任务将旧结果转换为对象吗? WebAPI 不处理实际 Task 的非泛型任务是否有原因?
  • 我会将此标记为答案,但我的实际问题是我是否可以让 WebApi 与作为任务公开的 Task 一起工作,这里是新问题stackoverflow.com/questions/29769261/…
  • “这样包装有什么影响”——我会说“最小”。该操作仍然是异步的,只是在调用堆栈中向下一层实现了延续。您确实使用了中间 Task 对象,但我认为这是不可避免的,特别是因为这个问题:您需要(显然)从预定义的 API 返回一个异步 object,但您的底层 API 返回一个特定类型.在某些时候,必须将特定类型解包并重新包装为适当的Task&lt;object&gt; 类型。额外的对象是最小的开销。
【解决方案2】:

您的问题是Task&lt;T&gt; 不是协变的,即您不能将Task&lt;Something&gt; 隐式转换为Task&lt;object&gt; - 例如,与从IEnumerable&lt;Something&gt;IEnumerable&lt;object&gt; 的转换不同。

解决此问题的最简单方法是将您的 Get 方法更改为 await 任务并在两个单独的语句中返回值,如下所示:

object obj = await ...;
return obj;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-10
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-21
    相关资源
    最近更新 更多