c# - 在 C# 8 中,如何检测不可能的空检查?

标签 c# null c#-8.0 nullable-reference-types

我已经开始在 C# 8 中使用可为 null 的引用类型。到目前为止,除了一件小事之外,我很喜欢这种改进。

我正在迁移一个旧的代码库,它充满了很多冗余或无法访问的代码,例如:

void Blah(SomeClass a) {
  if (a == null) {
    // this should be unreachable, since a is not nullable
  }
}

不幸的是,我没有看到任何可以为我标记此代码的警告设置!这是微软的疏忽,还是我遗漏了什么?

我也使用 ReSharper,但它的警告设置似乎也没有捕捉到这一点。有没有其他人找到解决这个问题的方法?

编辑:我知道从技术上讲这仍然可以访问,因为可空性检查不是防弹的。这不是重点。在这种情况下,我将参数声明为 不可为空 ,检查它是否为空通常是一个错误。在 null 作为不可空类型传入的罕见事件中,我更愿意看到 NullReferenceException并追踪错误传入 null 的违规代码。

最佳答案

值得注意的是,可空性检查不仅不是防弹的,而且它们旨在阻止调用者发送 null引用,他们没有做任何事情来阻止它。发送 null 的代码仍然可以编译到此方法,并且没有对参数值本身进行任何运行时验证。

如果您确定所有调用者都将使用 C# 8 的可空性上下文——例如,这是一个 internal方法— 您真的很努力地解决了 Roslyn 静态流分析中的所有警告(例如,您已将构建服务器配置为将它们视为错误),那么您正确地认为这些空检查是多余的。

the migration guide 中所述但是,任何不使用 C# 可空性上下文的外部代码都将完全忽略这一点:

The new syntax doesn't provide runtime checking. External code might circumvent the compiler's flow analysis.



鉴于此,在任何 public 中继续提供保护条款和其他可空性检查通常被认为是最佳实践。或 protected成员。

事实上,如果你使用微软的 Code Analysis package——我推荐它——它会警告你在这种情况下使用保护子句。他们考虑为 C# 8 的可空性上下文中的代码删除它,但是 decided to maintain it由于上述顾虑。

当您从代码分析中收到这些警告时,您可以将您的代码包装在空检查中,就像您在此处所做的那样。但是你也可以抛出异常。事实上,你可以再扔一个 NullReferenceException ——虽然绝对不推荐。在这种情况下,您应该抛出 ArgumentNullException ,并将参数的名称传递给构造函数:

void Blah(SomeClass a) {
  if (a == null) {
    throw new ArgumentNullException(nameof(a));
  }
  …
}

这比抛出 NullReferenceException 更受欢迎在源代码中,因为它通过显式命名作为 null 传递的确切参数(在本例中)来向调用者传达他们可以做些什么来避免这种情况。 .这比仅仅获得 NullReferenceException 更有用- 并且,可能是对您的内部代码的引用 - 发生异常的地方。

至关重要的是,此异常并不是要帮助您调试代码——这正是代码分析为您所做的。相反,它表明您已经确定了对空值的潜在取消引用,并且您已经在源头考虑了它。

Note: These guard clauses can add a lot of clutter to your code. My preference is to create a reusable internal utility that handles this via a single line. Alternatively, a single-line shorthand for the above code is:

void Blah(SomeClass a) {
  _ = a?? throw new ArgumentNullException(nameof(a));
}


这是回答您的原始问题的一种非常迂回的方式,即如何检测 C# 的不可空引用类型所不需要的空检查的存在。

简短的回答是你不能;在这一点上,Roslyn 的静态流分析侧重于识别取消引用空对象的可能性,而不是检测潜在的无关检查。

但是,如上所述,答案很长,您不应该这样做;直到微软 adds runtime validation ,或要求可空性上下文,这些空检查继续提供值(value)。

关于c# - 在 C# 8 中,如何检测不可能的空检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61000518/

相关文章:

c# - 顺序敏感调用的设计模式

c# - 分享 Windows Phone 8.1 C# 中的两个不同的东西

c - 我的 fgets 实现像 fgets 一样读取实际内容,但如果在文件中找到 NULL 字符串,它会读取垃圾?

c# - 使用 EnumeratorCancellation 返回 AsyncEnumerable 或循环 WithCancellation 有什么区别

C#8 可空和不可空引用类型 - 仅当输入可为空时输出可为空

c# - 在 foreach 循环中等待的正确方法

c# - 如何基于 x86/x64 获取不同的输出文件名

javascript - 正则表达式,选择其他文本中的一部分

sql - 在 SQL Server 2005 中使用 SSIS 从平面文件导入时如何保留 NULL 值

c++ - 缓冲区的动态内存分配