火和忘记方法

Mat*_*ith 38 c# async-await

此答案相关,

如果我真的想要"Fire and Forget"一个确实返回任务的方法,并且(为简单起见)让我们假设该方法不会抛出任何异常.我可以使用答案中列出的扩展方法:

public static void Forget(this Task task)
{
}
Run Code Online (Sandbox Code Playgroud)

使用这种方法,如果存在错误,则会Task引发异常,然后抛出意外异常时,异常将被吞下并被忽视.

问题:在这种情况下,扩展方法的形式是否更合适:

public static async void Forget(this Task task)
{
    await task;
}
Run Code Online (Sandbox Code Playgroud)

因此编程错误会引发异常并升级(通常会导致进程失效).

在具有预期(和可忽略的)异常的方法的情况下,该方法需要变得更加精细(除此之外,关于如何构建此方法的版本的任何建议将采用可接受和可忽略的异常类型的列表? )

Ste*_*ary 46

这取决于你想要的语义.如果你想确保注意到异常,那么是的,你可以await完成任务.但在那种情况下,它不是真正的"火与忘记".

一个真正的"火与忘记" - 从某种意义上说,你不关心它何时完成,或者它是成功完成还是错误 - 是非常罕见的.

编辑:

处理异常:

public static async void Forget(this Task task, params Type[] acceptableExceptions)
{
  try
  {
    await task.ConfigureAwait(false);
  }
  catch (Exception ex)
  {
    // TODO: consider whether derived types are also acceptable.
    if (!acceptableExceptions.Contains(ex.GetType()))
      throw;
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我建议使用await而不是ContinueWith.ContinueWith 有一个令人惊讶的默认调度程序(如我的博客中所述),Task.Exception并将实际的异常包装在一起AggregateException,使错误处理代码更加繁琐.

  • 那么,当一些事情结束时,我如何得到不关心的语义,但我是否关心例外?是否有可能在某种程度上没有"async void"的那些语义? (4认同)
  • `catch`块不会在捕获的上下文中运行(因此任何日志记录或其他任何内容都不会),但如果异常不可接受并且被重新抛出(`throw;`),则是,异常将是(重新)在`Forget`开头活动的`SynchronizationContext`上提出. (4认同)
  • 是你想太多还是我没明白?听起来你需要“try”/“catch”。编辑以显示示例代码。 (2认同)
  • [实际上,它称之为"Post"](http://referencesource.microsoft.com/#mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs#979). (2认同)