【问题标题】:How to indicate when purposely ignoring a return value如何在故意忽略返回值时进行指示
【发布时间】:2010-12-04 05:03:26
【问题描述】:

在某些使用 C/C++ 的情况下,我可以在语法上向编译器指示有意忽略返回值:

int SomeOperation()
{
    // Do the operation

    return report_id;
}

int main()
{
    // We execute the operation, but in this particular context we
    // have no use of the report id returned.
    (void)SomeOperation();
}

我认为这是一种公平的做法,首先因为大多数编译器不会在此处生成警告,其次因为它向未来的开发人员明确表明作者有意识地选择忽略返回。它使作者的思想轨迹不模棱两可。

据我所知,C# 编译器不会抱怨隐式忽略的返回值,但我想知道是否有类似的约定可以使用,以便向其他开发人员做出明确的指示。

这里有些人质疑这个约定的实际使用(或者如果有一个可能不重要的返回值的方法会显示出糟糕的设计)。

一个真实的 .NET 示例(我可能应该从一开始就基于这个问题)是 Mutex::WaitOne() 重载,它不接受任何参数。只有当互斥锁被安全获取时它才会返回,否则它永远不会返回。布尔返回值用于其他重载,在这些重载中,当它返回时您可能最终无法拥有互斥锁。

因此,按照我的推理,我想在我的多线程代码中表明我已选择忽略返回:

Mutex mtx = new Mutex();
(void)mtx.WaitOne();

因为返回值只能是true

【问题讨论】:

  • 然而WaitOne的超载有一个超时参数,当超时到期时会返回false。
  • @Pop:这就是我的论点。也许你看错了。
  • @R.A.由于您没有使用返回值(始终为真),这意味着您忽略了它,但是在您的示例中也没有约定说“我故意忽略它”返回值总是可以忽略按照设计,所以不需要额外的解释。

标签: c# syntax return-value


【解决方案1】:

从 C# 7.0 开始,您可以使用丢弃运算符“_”指示有意忽略的返回值。

int SomeOperation()
{
    return report_id;
}

int main()
{
    _ = SomeOperation();
}

有关详细信息,您可以查看 Microsoft 文档 here

【讨论】:

    【解决方案2】:

    如果您想向其他开发人员表明并明确表示有意忽略返回值,只需注释即可。

    SomeMethod(); // return value ignored - $REASON
    

    【讨论】:

      【解决方案3】:

      我只能想到一种情况,在 C# 中不允许忽略“返回值”:发生错误时。这应该通过抛出异常来提供,这使得它不可能被忽略。

      在其他情况下,忽略返回值是(或更好:必须是)完全安全且完全没有异味的。

      我还是看不懂重点。为什么要改进代码?您通过不将返回值分配给变量来指定忽略返回值。

      • 如果您的代码中不需要此值,一切都很好。
      • 如果需要,您将无法编写代码。
      • 如果存在必须处理且绝不能隐式忽略的特殊情况,则应引发异常。
      • 如果被调用的方法没有返回值并且稍后得到一个,则必须将其设计为不会破坏忽略它的现有代码。现有的调用代码不会改变。

      我忘了一个箱子吗?

      【讨论】:

      • 很好的答案,因为不应该在 .Net 中返回错误代码,所有其他值都可以安全地忽略,因为它们应该只代表计算结果或其他不代表错误状态的信息。
      • 强烈反对it is (...) not smelly at all to ignore return values,阅读有关方法的Pure 属性。不使用纯方法的返回值肯定是一个错误。例如。写startDate.AddDays(1) 使startDate 保持不变并返回一个新日期,即未来一天,忽略该新日期表示开发人员认为 startDate 已更改。
      • @ANeves:除非程序员完全误解了一个方法实际上在做什么(这应该通过适当的命名来解决),否则他不能在不使用返回值的情况下继续进行。那么他为什么要计算一个日期+1天而不使用结果呢?如果他不使用它,他就不需要计算它。您说 AddDays 实际在做什么对每个人来说并不明显。但这与返回值问题有什么关系?这是一个命名问题。
      • @PopCatalin:“错误代码不应在 .NET 中使用..”您为什么认为这是普遍正确的?
      • @TonyBasile 因为 .Net 有异常作为错误处理机制,所有库都围绕它展开,一般的期望是 .Net 中的错误条件作为异常返回。错误代码必须在本地处理,而异常可以在调用链上的任何地方处理,通常.Net 应用程序是围绕这个假设构建的,错误处理程序位于特定(通常是顶层)位置,而不是在每个方法中。使用错误码的代码看起来很不一样,每次方法调用后都有错误检查,这不是 .Net 代码通常的样子。
      【解决方案4】:

      Microsoft C# 编译器不会在忽略返回时生成警告。不需要,因为有一个垃圾收集器,所以不会因为忽略返回的对象而导致任何内存泄漏(当然,除非它们是 IDisposable 的)。因此,无需显式“覆盖”编译器。

      编辑:另外,我认为“可维护性”问题更像是文档和命名实践问题。我知道这只是一个示例,但您不会期望名为SomeOperation 的方法返回ReportId。但是,您会期望 GetReportId 方法返回 ReportId 而不会产生很多副作用。事实上,忽略名为GetReportId 的方法的返回值会很奇怪。因此,请确保您正确命名您的方法,这样人们就不会怀疑您的函数调用的效果。

      编辑 2: 在这个互斥体示例中,我相信正确的用法实际上是不忽略返回值。即使当前的实现永远不会返回 false,我认为仍然检查返回值是一个好习惯,以防万一您将来最终会使用另一个实现,或者它们在 .NET Framework 的未来版本中改变行为或某事:

      if (mutex.WaitOne())
      {
         // Your code here
      }
      else
      {
         // Optionally, some error handling here
      }
      

      【讨论】:

      • 明白。但正如我在问题中提到的,我想使用约定向其他开发人员明确表明我故意忽略返回。我会更新它以使其更清晰。
      【解决方案5】:

      object dummy = JustDontCare();

      【讨论】:

      • 传统名称是“虚拟”变量。
      • (来自 Chris KL)...向正在查看代码的未来编码人员表明您非常清楚它会返回一些内容,而您故意忽略它。
      • @Charlie - 就我个人而言,我只会删除变量,但这没有抓住问题的重点。这个想法是合理的。有些语言强迫你做这种事情,因为他们认为隐式丢弃返回值是邪恶的。
      • 这种方式会触发代码分析规则CA1804: Remove unused locals
      • 我认为更规范的方法显示在@bbartels 答案中(假设 C# 7.0+)。
      【解决方案6】:

      没有我知道的标准约定。

      但我正在努力寻找需要这个的充分理由。听起来 SomeOperation() 真的应该是两个独立的方法。你有一个真正应该这样做的方法的例子吗?如果方法将被忽略,为什么还要费心返回结果?

      【讨论】:

      • 你真的要重构只是因为有一个地方你不需要函数的返回值吗?就个人而言,我可能编写了一个小函数,它只使用本地虚拟变量调用现有的结果,但本身不返回任何内容 - 但很可能不会。当然,我同意,如果它会被忽略,为什么要返回一个结果,但又为什么有两个几乎相同的函数呢?为什么更喜欢过早的优化而不是清理、最小化混乱的代码?此外,无论如何,该函数可能是内联和编译器优化的。
      • Steve314 - 我并不是说它必须需要重构。我试图暗示这对我来说似乎是一种代码味道。因此,我想确保这是一个真正的问题,而不仅仅是由其他东西造成的。
      • @Matt - IMO 这不是真正的代码气味。我见过太多返回值的函数,基本上是因为它无论如何都是计算出来的,而且它通常很有用。还有许多函数返回成功标志,但有时上下文无论如何都保证返回真类型的成功。有 很好的理由忽略返回值。这不是常态,但远非不寻常。我同意你声称的动机,但你的答案的最后一句话读作讽刺批评 - 以及无效的讽刺批评,因为任何一个函数都可以有很多调用者。
      【解决方案7】:

      有时,能够放入 (void) 以向正在查看代码的未来编码人员表明您非常清楚它返回了某些内容,而您故意忽略它,这很有用。

      也就是说,C# 编译器会在语法上出错。

      【讨论】:

        【解决方案8】:

        我见过:

        var notUsed = SomeOperation();
        

        虽然不是很喜欢。

        【讨论】:

        【解决方案9】:

        .Net 中的约定是,如果您不存储或使用意味着您隐式忽略它的返回值,则没有明确的约定,并且 API 通常设计为通常可以忽略返回值,但例外代表失败、成功状态的布尔值。

        但即使在布尔返回值表示成功/失败状态的情况下,约定是如果您忽略返回值(不要使用它),这意味着代码不依赖于先前调用的成功状态.

        【讨论】:

        • 我很欣赏 C# 中有些事情是常见的做法,但总的来说(特别是对于大型项目),当作者的思路清晰且清晰时,代码的质量总是会提高没有歧义。
        • 好吧,如果您担心代码质量,那么忽略可以“安全”忽略且不需要的返回值不会提高代码质量。如果需要解释为什么忽略该值,但不需要,那么注释会更充分,因为它会解释“为什么”,而不是说明明显的“忽略该值”。没有约定说明显而易见的(返回值被忽略),因为忽略返回值很少和错误,它通常是在.Net中选择的。
        猜你喜欢
        • 2019-05-04
        • 1970-01-01
        • 2021-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-21
        • 1970-01-01
        • 2012-08-06
        相关资源
        最近更新 更多