【问题标题】:Why is CS4014 not shown for all functions that return a task?为什么没有为所有返回任务的函数显示 CS4014?
【发布时间】:2018-01-18 17:36:46
【问题描述】:

假设如下代码:

private async Task Test1Async() => await Task.Delay(1000).ConfigureAwait(false);
private Task Test2Async() => Test1Async();

在功能上,这些函数完全相同,但编译器对调用这些方法的处理不同。以下代码编译,但发出 CS4014 警告:

private void Test() => Test1Async();   // CS4014 is shown

它会生成警告“因为没有等待此调用,所以当前方法在调用完成之前继续运行”。这是一个正确的警告,因为它通常表明您的代码中存在缺陷。如果您真的想要这种行为,那么您可以使用以下代码来解决它:

private void Test() => _ = Test1Async();   // CS4014 is not shown anymore

将值分配给_ 是一项相对较新的功能,表示有意忽略该值。

此代码不会引发 CS4014:

private void Test() => Test2Async();   // CS4014 is not shown!

当然,我可以重写所有方法以使用async/await 方法,但这会导致更多代码运行效率降低(由于async 关键字生成的状态机)。也许我永远不会忘记它,但我的同事可能会然后我不会得到触发器(或者我调用不使用异步的第三方库)。

关于返回的Task使用情况的警告也有所不同。

有谁知道为什么不为返回 Task 且不使用 async 关键字的方法生成此警告?

【问题讨论】:

  • 隐藏在语法糖中。该分配确保 Task.Result 属性得到评估。从而确保任务完成。过多的糖确实会导致蛀牙。
  • @HansPassant 哪个 Task.Result 属性?一个简单的任务(非泛型)是否有任何 Result 属性?
  • 第二种情况:Test2Async()没有标记async,所以这个方法本身不认为是“在调用完成前继续[ing]运行” .它确实没有,这个方法在它返回时完全完成。 “继续运行”的是Test1Async()
  • 我的 goolge 似乎坏了,你能告诉我这个 _ = Test1Async() 构造的文档/规范的链接吗?这是c#7还是6,我找不到。它有名字吗?
  • @RenéVogt:这里提到:blogs.msdn.microsoft.com/dotnet/2017/03/09/…;在页面中搜索“丢弃”。

标签: c# async-await


【解决方案1】:

有谁知道为什么不为返回 Task 且不使用 async 关键字的方法生成此警告?

可能是为了避免对遗留代码的虚假警告。 Task 早于 async,并且有许多方法返回 Task 但与异步代码没有任何关系。

就个人而言,我认为忽略Task 返回值几乎可以肯定是一个错误,即使在非异步代码中也是如此。但我假设 MS 团队运行了指标并确定此警告对于这些类型的代码库来说过于嘈杂。

【讨论】:

  • 我认为忽略Task 在这两种情况下都值得生成CS4014,而且看起来更一致。这是一个警告,因此为两种样式启用它实际上不会破坏任何东西。我一直认为async 关键字是在底层生成复杂状态机的语法糖。但最终结果只是一个返回Task 的普通函数。这就是为什么我认为它应该被同样处理。据我所知,TPL 是在 .NET 4 中引入的,而 async 关键字是在 .NET 4.5 时代引入的……
  • 我已向 Roslyn 团队提交了一个关于此问题的问题 (github.com/dotnet/roslyn/issues/21428)。希望他们能澄清或解决这个问题......
  • 你是对的。请参阅 Roslyn 团队的此评论:github.com/dotnet/roslyn/issues/20782#issuecomment-316764474:“此行为是“设计使然”。编译器只会为显式标记的异步方法发出 CS4014。让它为所有返回 Task 的方法发出警告是一个重大的兼容性问题。 "
【解决方案2】:

没有发出警告,因为没有Task 掉在地板上。 Task 被返回,所以调用者完全有能力观察它。存在警告以指出未观察到的任务。产生警告将是错误

代码正确;为正确代码生成警告是非常有问题的,因为它可能会导致程序员将其更改为不正确的代码,更糟糕的代码,在那里对问题所在感到困惑(因为没有一)或者,至少,他们需要花费额外的工作来解决错误的警告。

【讨论】:

  • 这两种方法都返回一个任务,你是对的。确实是调用者有责任对任务执行某些操作。警告用于指示您的代码中可能存在的问题。忽略任务(默默地)是一个潜在的问题,所以最好发出警告。 C# 7 有一个很好的方法 (_) 来表明你想忽略一个结果。
猜你喜欢
  • 2022-12-18
  • 1970-01-01
  • 2021-04-14
  • 2012-09-07
  • 1970-01-01
  • 2013-03-25
  • 2014-03-06
相关资源
最近更新 更多