如果我不等待任务会怎样?

考虑这个例子:

var task = DoSomething() bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse return value + await task; 

DoSomething做了一些可能需要一段时间的非常重要的工作,因此我们首先开始它。
与此同时,我们会检查我们是否已准备好使用DoSomethingElse ,如果没有,我们会提前退出。
我们只有ready 才会调用DoThirdThing ,因为宇宙可能会爆炸。

我们不能使用Task.WhenAll因为DoThirdThing依赖于DoSomethingElse ,我们也不想等待DoSomething因为我们想要尽可能同时调用其他两个方法。

问题是:如果我们还没有ready并提前退出,会发生什么?

它会抛出的任何exception会被SynchronizationContext重新抛出吗?
如果task正常完成,是否存在问题,因为没有人消耗它的价值?

后续行动:有没有一种巧妙的方法来确保等待task

如果我们还没ready ,我们可以简单地await task ,但是如果有50个退出条件,那将非常繁琐。
是否可以使用finally块来await task并重新抛出潜在的exception? 如果task正常完成,则会在finally块中再次等待,但这不会导致任何问题吗?

问题是:如果我们还没有准备好并提前退出,会发生什么?

没有。 代码忽略任务,因此忽略该任务。

它会抛出的任何exception会被SynchronizationContext重新抛出吗?

不会。他们将(最终)传递给TaskScheduler.UnobservedTaskException然后被忽略。

如果任务正常完成,是否存在问题,因为没有人消耗它的价值?

不。

后续行动:有没有一种巧妙的方法来确保等待任务?

没有。

是否可以使用finally块来等待任务并重新抛出潜在的exception?

是的,如果您的代码实际await任务。 据推测,这意味着在某处保存任务。

如果任务正常完成,则会在finally块中再次等待,但这不会导致任何问题吗?

您可以根据需要多次await任务。

如果我们还没准备好,我们可以简单地等待任务,但是如果有50个退出条件,那将非常繁琐。

然后考虑重组您的代码。

后续行动:有没有一种巧妙的方法来确保等待任务?

如果您需要单独的,比TaskScheduler.UnobservedTaskException更细粒度地控制您不await的任务抛出的exception,那么有一个方便的工具: async void方法。

您的代码可能如下所示:

 static async void Observe(Task task) { // use try/catch here if desired so; // otherwise, exceptions will be thrown out-of-band, ie // via SyncronizationContext.Post or // via ThreadPool.QueueUSerWorkItem (if there's no sync. context) await task; } // ... var taskObserved = false; var task = DoSomething() try { bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse taskObserved = true; return value + await task; } finally { if (!taskObserved) Observe(task); } 

在这里和这里可以找到更多细节。