[英]Calling an async method from a non-async method
我尝试的以下代码的每个变体都不起作用 - 无论是DoSomething() : void
并按写入方式调用,还是DoSomething() : Task
并使用TaskEx.RunEx()
调用,一些尝试涉及.GetAwaiter().GetResult()
。 看到的错误包括: "Start may not be called on a task with null action"
、 "RunSynchronously may not be called on a task unbound to a delegate"
和"The task has not yet completed"
。
class Program
{
static void Main(string[] args) // Starting from a non-async method
{
DoSomething();
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static async void DoSomething()
{
Console.WriteLine("Starting DoSomething ...");
var x = await PrepareAwaitable(1);
Console.WriteLine("::" + x);
var y = await PrepareAwaitable(2);
Console.WriteLine("::" + y);
}
static Task<string> PrepareAwaitable(int id)
{
return new Task<string>(() =>
{
return "Howdy " + id.ToString();
});
}
}
输出:
开始做某事...
按任意键退出。
PrepareAwaitable
的Task
的Action
后面会比较复杂。 当此操作完成时,无论需要多长时间,我都希望通过将"Howdy ..."
分配给 x,然后再分配给 y 来恢复Task
(或其他框架机制)。 我真正想要做的是拦截等待的对象,处理它们,然后在我控制的稍后时间,以结果( x
和y
)恢复到延续。 但是我在这大步上还没有走得很远,所以我试图从小处开始。
首先,阅读基于任务的异步模式文档。 它位于My Documents\\Microsoft Visual Studio Async CTP\\Documentation
。 本文档描述了如何设计await
自然使用的 API。
其次,要意识到Task
类和相关 API 的几个方面不再真正适用于新的异步世界。 Task
最初是作为 TPL 的核心编写的。 结果证明它非常适合异步编程,所以微软使用它而不是创建一个新的“Promise”类。 但是许多方法是保留的,由 TPL 使用,但不需要异步编程。
为了回答名义上的问题,使用当前的异步 CTP 混合同步和异步代码并不是很简单。 我编写了一个包含Task.WaitAndUnwrapException
扩展方法的库,它可以轻松地从同步代码调用异步代码。 您可能还对我的AsyncContext
类感兴趣,这使得“按任意键”提示变得不必要。
真的不清楚你想要实现什么,因为没有任何异步发生。 例如,这将编译并运行,但我不知道它是否是您想要的:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
DoSomething();
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static async void DoSomething()
{
Console.WriteLine("Starting DoSomething ...");
var x = await PrepareAwaitable(1);
Console.WriteLine("::" + x);
var y = await PrepareAwaitable(2);
Console.WriteLine("::" + y);
}
static async Task<string> PrepareAwaitable(int x)
{
return "Howdy " + x;
}
}
请注意,这会为PrepareAwaitable
发出警告,因为其中没有任何异步内容; 没有“等待”表达。 整个程序同步执行。 PrepareAwaitable
另一种替代实现:
static Task<string> PrepareAwaitable(int x)
{
return TaskEx.Run(() => "Howdy " + x);
}
这更像你追求的吗?
您返回的任务尚未开始(即它们是“冷”任务); 尝试用以下代码替换 PrepareAwaitable 代码:
static Task<string> PrepareAwaitable(int x)
{
return Task.Factory.StartNew<string>(() =>
{
return "Howdy " + x.ToString();
});
}
在您的异步任务应该工作之后添加GetAwaiter().GetResult()
。 但是为了消除诸如“...不要在具有空操作的任务上调用”之类的错误,您只需让Task<IHttpActionResult>
返回 Ok(true) 而不是 Ok()。 它为我解决了 GetResult() 问题!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.