Visual Studio会对此代码发出警告('因为不等待此调用,在调用完成之前会继续执行当前方法'。)
static void Main(string[] args)
{
FireAndForget(); // <-- Warning CS4014
// Do something else.
}
static async Task FireAndForget()
{
// Do something (cannot throw).
}
我的理解是,在这种特殊情况下不等待任务是可以的,因为FireAndForget永远不会抛出异常。
我没有考虑使用pragma禁用警告,而是考虑将FireAndForget的返回类型从Task更改为void。这有效地使编译器沉默。
static async void FireAndForget() // <-- Task changed to void
{
// Do something (cannot throw).
}
然而,根据Stephen Cleary,应该避免使用'async void'方法,因此我不太清楚该怎么做。
如果方法不是设计为首先等待并且没有抛出异常,那么是否可以使用'async void'方法?
答案 0 :(得分:12)
非常很少有真正的“即发即弃”操作;也就是说,一个操作:
特别是最后一个;最所谓的“即发即忘”&#34;操作实际上并不是一劳永逸,因为如果它没有成功就需要采取一些行动。
也就是说,在某些情况下可以使用真正的“即发即弃”。
我更喜欢使用async Task
并通过将任务分配给其他未使用的变量来避免编译器警告:
var _ = FireAndForget();
async Task
方法比async void
方法更具可重用性和可测试性。
但是,如果我的团队中的开发人员只使用async void
,我就不会适合。
答案 1 :(得分:2)
是否可以拥有“异步空白”#39;方法如果没有设计 首先是等待,如果不会抛出异常?
虽然它可能是&#34;好的&#34;要这样做,我仍然鼓励你制作方法async Task
。尽管你百分之百地确定这种方法不会被抛弃,而且还没有被期待,但你永远不知道它最终会被如何使用。您现在已经充分意识到使用async void
的后果是什么,但是如果将来有人可能需要使用它,那么您最好放置一个很好的评论为什么这个Task
没有被等待,而不是顺利地做出这个void
。
不要让编译器警告让您担心,我会担心这可能对您的代码库产生正确性和影响。
答案 2 :(得分:1)
有时您想解雇,但是对于某些人,您应该始终将其明确地表达出来,以使其能读懂代码。我发现“ _”表示法不够明确,因此使用扩展方法来做到这一点:
public static class TaskExtensions()
{
public static void InvokeAndIgnore(this Task fireAndForgetTask)
{
// deliberately do nothing; used to suppress warning
}
}
您可以按以下方式使用它:
worker.AttemptCloseAsync().InvokeAndIgnore();
答案 3 :(得分:0)
一个潜在的问题是,现在无法判断代码是否引发了异常。因此,如果你有单元测试来检测这些,单元测试将无法工作。
来自MSDN网站的经典示例:
private async void ThrowExceptionAsync() { throw new InvalidOperationException(); } public void AsyncVoidExceptions_CannotBeCaughtByCatch() { try { ThrowExceptionAsync(); } catch (Exception) { // The exception is never caught here! throw; } }
http://haacked.com/archive/2014/11/11/async-void-methods/
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
如果这是一个特定的边缘情况,而不是使用async void
,那么使用pragma语句怎么样?
#pragma warning disable CS-4014
... your code here ...
#pragma warning restore CS-4014
这样你可以调出静电噪音。
... HTH