是否可以将async方法声明为返回void以使CS4014警告静音?

时间:2015-09-24 16:04:56

标签: c# async-await

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'方法?

4 个答案:

答案 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