与异步方法相关的VoidTaskResult类型是什么? [英] What is the type VoidTaskResult as it relates to async methods?

查看:89
本文介绍了与异步方法相关的VoidTaskResult类型是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我第一次使用异步(实际上是.Net 4.5),遇到了让我感到困惑的事情。我在网上找不到关于 VoidTaskResult 类的信息,所以我来这里看看是否有人对发生的事情有任何了解。

I've been using async (and .Net 4.5 really) for the first time recently, and I've come across something that has me stumped. There isn't much information about the VoidTaskResult class that I can find on the Net so I came here to see if anyone has any ideas about what is going on.

我的代码如下。显然,这大大简化了。基本思想是调用异步的插件方法。如果它们返回 Task ,则异步调用没有返回值。如果它们返回 Task<> ,则存在。我们事先不知道它们是哪种类型,因此我们的想法是使用反射来查看结果的类型(如果类型为<$ c,则 IsGenericType 为true $ c> Type<> )并使用动态类型获取值。

My code is something like the following. Obviously, this is much simplified. The basic idea is to call plugin methods, which are asynchronous. If they return Task, then there is no return value from the async call. If they return Task<>, then there is. We don't know in advance which type they are, so the idea is to look at the type of the result using reflection (IsGenericType is true if the type is Type<>) and get the value using a dynamic type.

在我的真实代码中,我正在调用plugin方法通过反射。我认为这不会改变我所看到的行为。

In my real code, I am calling the plugin method via reflection. I don't think this should make a difference to the behaviour I am seeing.

// plugin method
public Task yada()
{
 // stuff
}

public async void doYada()
{
  Task task = yada();
  await task;

  if (task.GetType().IsGenericType)
  {
    dynamic dynTask = task;
    object result = dynTask.Result;
    // do something with result
  }
}

此适用于上面显示的插件方法。 IsGenericType 是错误的(与预期的一样)。

This works good for the plugin method shown above. IsGenericType is false (as expected).

但是,如果您稍微改变插件方法的声明, IsGenericType 现在返回true,并且出现中断:

However if you change the declaration of the plugin method ever so slightly, IsGenericType now returns true and stuff breaks:

public async Task yada()
{
 // stuff
}

这样,在 object result = dynTask.Result; c:

如果您深入研究任务对象,它实际上似乎是 Type< VoidTaskResult> VoidTaskResult 是线程名称空间中的私有类型,几乎没有任何内容。

If you dig into the task object, it actually appears to be Type<VoidTaskResult>. VoidTaskResult is a private type in the Threading name space with almost nothing in it.

我尝试更改呼叫代码:

public async void doYada()
{
  Task task = yada();
  await task;

  if (task.GetType().IsGenericType)
  {
    object result = task.GetType().GetProperty("Result").GetMethod.Invoke(task, new object[] { });
    // do something with result
  }
}

此成功,它不再抛出,但现在的结果是 VoidTaskResult 类型,我无法明智地对其进行任何处理。

This "succeeds" in the sense that it no longer throws, but now result is of the type VoidTaskResult which I cannot sensibly do anything with.

我还要补充一点,即使为所有这些问题提出一个真正的问题,我也很难。也许我真正的问题是什么是 VoidTaskResult ?或为什么在我动态调用异步方法时会发生这种奇怪的事情?甚至可能是如何调用可选的异步异步方法?无论如何,我都希望这样做,以希望其中一位大师能够阐明一些观点。

I should add that I'm having a hard time even formulating a real question for all this. Maybe my real question is something like "What is VoidTaskResult?", or "Why does this weird thing happen when I call an async method dynamically?" or possibly even "How do you call plugin methods that are optionally asynchronous?" In any case, I am putting this out there in the hope that one of the gurus will be able to shed some light.

推荐答案

这是由于围绕任务(特别是任务完成源)的类层次结构的设计方式。

This is due to the way the class hierarchy around tasks (and particularly task completion sources) is designed.

首先, Task< T> 源自 Task 。我认为您已经很熟悉。

First off, Task<T> derives from Task. I assume you're already familiar with that.

此外,您可以创建 Task Task< T> 用于执行代码的任务。例如,如果您的第一个示例返回了 Task.Run 或其他,那将返回一个实际的 Task 对象。

Furthermore, you can create types of Task or Task<T> for tasks that execute code. E.g., if your first example was returning Task.Run or whatnot, then that would be returning an actual Task object.

当您考虑 TaskCompletionSource< T> 如何与任务层次结构交互时,就会出现问题。 TaskCompletionSource< T> 用于创建不执行代码的任务,而是充当某些操作已完成的通知。例如,超时,I / O包装器或 async 方法。

The problem comes in when you consider how TaskCompletionSource<T> interacts with the task hierarchy. TaskCompletionSource<T> is used to create tasks that don't execute code, but rather act as a notification that some operation has completed. E.g., timeouts, I/O wrappers, or async methods.

没有非泛型的 TaskCompletionSource 类型,因此,如果您希望这样的通知没有返回值(例如,超时或 async Task 方法),则您必须为某些 T 创建一个 TaskCompletionSource< T> 并返回 Task< T> ; async 团队必须为 async Task 选择一个 T 方法,因此他们创建了 VoidTaskResult 类型。

There is no non-generic TaskCompletionSource type, so if you want to have notification like this without a return value (e.g., timeouts or async Task methods), then you have to create a TaskCompletionSource<T> for some T and return the Task<T>. The async team had to choose a T for async Task methods, so they created the type VoidTaskResult.

通常这不是问题。由于 Task< T> 源自 Task ,因此该值将转换为 Task ,每个人(在静态世界中)都很高兴。但是,由 TaskCompletionSource< T> 创建的每个任务实际上都是 Task< T> 类型,而不是任务,然后您会通过反射/动态代码看到它。

Normally this is not a problem. Since Task<T> derives from Task, the value is converted to Task and everyone is happy (in the static world). However, every task created by TaskCompletionSource<T> is actually of type Task<T>, not Task, and you see this with reflection/dynamic code.

最终结果是您必须处理 Task< VoidTaskResult> 就像是 Task 一样。但是, VoidTaskResult 是一个实现细节。

The end result is that you have to treat Task<VoidTaskResult> just like it was Task. However, VoidTaskResult is an implementation detail; it may change in the future.

因此,我建议您实际上基于(声明的)返回类型 yada ,而不是(实际)返回值。

So, I recommend that you actually base your logic on the (declared) return type of yada, not the (actual) return value. This more closely mimics what the compiler does.

Task task = (Task)yadaMethod.Invoke(...);
await task;

if (yadaMethod.ReturnType.IsGenericType)
{
  ...
}

这篇关于与异步方法相关的VoidTaskResult类型是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆