我使用的库提供以...Async
结尾的方法并返回Task
。我将在命令行应用程序中使用它们。所以我需要同步调用它们。
当然,C#不允许在Main
方法中调用这些方法,因为您无法在async
方法上使用Main
修饰符。假设这是任务:
var task = datastore.Save(data);
我找到了几个解决方案,如:
Tasks.WaitAll(task);
task.Wait();
然而,AggregateException
中所有这些包装抛出异常,我不希望。我只想说task.Result
,我希望抛出原始异常。
当我使用返回Task<TResult>
的方法时,task.Result
会抛出AggregateException
,即使没有设置连续任务。为什么这是hapening?
我也试过了,
task.RunSynchronously();
它给出错误:
可能不会在未绑定到委托的任务上调用RunSynchronously,例如从异步方法返回的任务。
所以我想这不是标记为async
的方法。
在没有异步上下文的控制台应用程序中使用为异步应用程序设计的库的模式的任何想法?
答案 0 :(得分:31)
我将在命令行应用程序中使用它们。所以我需要同步调用它们。
不,你没有。您可以在控制台应用程序中使用async
- await
,您只需要在最顶层进行异步同步转换。你可以使用Wait()
:
public static void Main()
{
MainAsync().Wait();
}
public static async Task MainAsync()
{
var datastore = …;
await datastore.SaveAsync();
}
通常情况下,将await
与Wait()
合并是一个坏主意(它可能会导致死锁),但这是正确的解决方案。
请注意,如果SaveAsync()
引发异常并且您没有抓住它,则会从AggregateException
重新引用Wait()
。但您可以将其作为MainAsync()
中的原始异常(因为它不使用Wait()
)来捕获它。
如果你真的想直接抛出第一个异常,你可以做类似于await
做的事情:task.GetAwaiter().GetResult()
。请注意,如果Task
包含多个例外,则只会获得第一个例外(但同样适用于await
)。
当我使用返回
Task<TResult>
的方法时,task.Result
会抛出AggregateException
,即使没有设置连续任务。为什么会这样?
这与延续无关。单个Task
可以表示多个操作,每个操作都可以抛出异常。因此,Task
方法总是抛出包含在AggregateException
中的异常。
我也尝试了
task.RunSynchronously()
这没有任何意义。 RunSynchronously()
只能在使用Task
构造函数创建的Task
上使用。这不是这种情况,所以你不能使用它。从异步方法返回的Task
始终已经启动。
答案 1 :(得分:2)
您可以创建一个虚拟Main
public static void Main()
{
MainAsync().Wait();
}
public static async Task MainAsync()
{
try {
var result = await dataStore.Save(data);
} catch(ExceptionYouWantToCatch e) {
// handle it
}
}
答案 2 :(得分:0)
As of C# 7.1 you can now declare the Main method as async. Just have to make sure your language is either set to default major version (which should work in VS 2019 now) or you can always target a specific version of the language.
See this link for details. Turn on async main