180*_*ION 9 c# reflection asynchronous dynamic
我最近第一次使用异步(和.Net 4.5),我遇到了让我难过的东西.关于我可以在网上找到的VoidTaskResult类的信息不多,所以我来到这里是为了看看是否有任何关于发生了什么的想法.
我的代码如下所示.显然,这很简单.基本思想是调用异步的插件方法.如果它们返回Task,则异步调用没有返回值.如果他们返回Task <>,那么就有了.我们事先不知道它们是哪种类型,因此我们的想法是使用反射查看结果的类型(如果类型为Type <>,则IsGenericType为true)并使用动态类型获取值.
在我的真实代码中,我通过反射调用插件方法.我认为这不应该对我所看到的行为产生影响.
// 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
}
}
Run Code Online (Sandbox Code Playgroud)
这适用于上面显示的插件方法.IsGenericType为false(正如预期的那样).
但是,如果稍微更改插件方法的声明,IsGenericType现在返回true并且东西中断:
public async Task yada()
{
// stuff
}
Run Code Online (Sandbox Code Playgroud)
执行此操作时,行上会抛出以下异常(object result = dynTask.Result;):

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

我尝试更改我的调用代码:
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
}
}
Run Code Online (Sandbox Code Playgroud)
这种"成功"意味着它不再抛出,但现在结果是"VoidTaskResult"类型,我无法明智地做任何事情.
我应该补充一点,即使为这一切制定一个真实的问题,我也很难.也许我真正的问题是"什么是VoidTaskResult?",或者"为什么当我动态调用异步方法时会发生这种奇怪的事情?" 甚至可能"如何调用可选的异步插件方法?" 在任何情况下,我都把它放在那里,希望其中一位大师能够解决这些问题.
Ste*_*ary 13
这是由于围绕任务(尤其是任务完成源)的类层次结构的设计方式.
首先,Task<T>源于Task.我假设你已经熟悉了.
此外,您可以创建执行代码的任务类型Task或Task<T>任务.例如,如果您的第一个示例是返回Task.Run或诸如此类,那么这将返回一个实际Task对象.
当您考虑如何TaskCompletionSource<T>与任务层次结构进行交互时,会出现此问题.TaskCompletionSource<T>用于创建不执行代码的任务,而是充当某些操作已完成的通知.例如,超时,I/O包装或async方法.
没有非泛型TaskCompletionSource类型,所以如果你想要这样的通知没有返回值(例如,超时或async Task方法),那么你必须TaskCompletionSource<T>为某些创建一个T并返回Task<T>.该async团队不得不选择T的async Task方法,所以他们创建的类型VoidTaskResult.
通常这不是问题.由于Task<T>派生自Task,价值被转换为Task每个人都很高兴(在静态世界中).但是,创建的每个任务TaskCompletionSource<T>实际上都是类型Task<T>,而不是Task,您可以使用反射/动态代码看到它.
最终的结果是你必须Task<VoidTaskResult>像对待那样对待Task.但是,VoidTaskResult是一个实现细节; 它可能会在未来发生变化.
因此,我建议您实际将逻辑基于(声明的)返回类型yada,而不是(实际)返回值.这更接近于模仿编译器的功能.
Task task = (Task)yadaMethod.Invoke(...);
await task;
if (yadaMethod.ReturnType.IsGenericType)
{
...
}
Run Code Online (Sandbox Code Playgroud)