24

我正在使用一个库,它提供以...Async和 return结尾的方法Task。我将在命令行应用程序中使用这些。所以我需要经常同步调用它们。

C# 当然不允许在方法中调用这些方法,Main因为您不能async在方法上使用修饰符Main。假设这是任务:

var task = datastore.Save(data);

我找到了几种解决方案,例如:

Tasks.WaitAll(task);
task.Wait();

但是所有这些将抛出的异常都包含在其中AggregateException我不希望这样。我只想说task.Result,我希望抛出原始异常。

当我使用方法时,即使没有设置继续任务Task<TResult>,也会task.Result抛出。AggregateException为什么会这样?

我也试过,

task.RunSynchronously();

它给出了错误:

不能在未绑定到委托的任务上调用 RunSynchronously,例如从异步方法返回的任务。

所以我想这不适用于标记为async.

关于在没有异步上下文的控制台应用程序中使用为异步应用程序设计的库的模式的任何想法?

4

3 回答 3

36

我将在命令行应用程序中使用这些。所以我需要经常同步调用它们。

不,你没有。您可以使用async-await在控制台应用程序中,您只需要在最顶部进行异步同步转换。你可以通过使用来做到这一点Wait()

public static void Main()
{
    MainAsync().Wait();
}

public static async Task MainAsync()
{
    var datastore = …;
    await datastore.SaveAsync();
}

通常,结合awaitwithWait()是一个坏主意(它会导致死锁),但这是正确的解决方案。

请注意,如果SaveAsync()抛出异常并且您没有捕获它,它将AggregateExceptionWait(). 但是您可以将其作为原始异常捕获MainAsync()(因为它不使用Wait())。

如果你真的想直接抛出第一个异常,你可以做类似的事情awaittask.GetAwaiter().GetResult()。请注意,如果Task包含多个异常,您将仅获得第一个异常(但同样适用于await)。

从 C# 7.1 开始,您可以制作Main方法async,编译器将为您编写转换代码:

public static async Task Main()
{
    var datastore = …;
    await datastore.SaveAsync();
}

当我使用方法时,即使没有设置继续任务Task<TResult>,也会task.Result抛出。AggregateException为什么会这样?

这与延续无关。一个Task可以代表多个操作,每个操作都可以抛出一个异常。因此,Task方法总是抛出包装在AggregateException.

我也试过task.RunSynchronously()

这没有任何意义。RunSynchronously()只能在Task使用构造函数创建的 s 上使用Task。这里不是这种情况,所以你不能使用它。Task从异步方法返回的 s 总是已经启动。

于 2013-07-16T10:48:42.983 回答
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
    }
}

另外,请参阅此答案: https ://stackoverflow.com/a/9212343/1529246

于 2013-07-16T05:35:07.293 回答
0

从 C# 7.1 开始,您现在可以将 Main 方法声明为异步。只需确保您的语言设置为默认主要版本(现在应该可以在 VS 2019 中使用),或者您始终可以针对特定版本的语言。

有关详细信息,请参阅此链接。开启异步主程序

于 2019-03-17T22:26:12.617 回答