为什么 C# 空引用警告在检测空检查方面仍然如此有限? [已关闭]

问题描述 投票:0回答:1

我说的是这样的情况:在抛出警告时,没有可能的路径导致特定变量为空。类似的问题以前已经被问过很多次了,尤其是在这里,我发现一个问题在很大程度上突出了这个问题,甚至 C# 程序经理也做出了回应:

为什么这段代码会给出“可能的空引用返回”编译器警告?

但是,我不明白给出的解释。或者更确切地说,他们确实谈论了缺乏复杂性,并且跟踪器仅跟踪变量内部值,而不跟踪它周围的程序流。我想提供一个我在 C# 中经常遇到的挫败感的例子,它不会导致例如以下问题: Java 根本:

public double DoSomething(MyClass obj)
{
  if (obj is null) throw new ArgumentException("Object is null!");
  
  var result = OtherMethodCall(obj.A);
  // or alternative example:
  var result = obj.A * 10 / 3;
  
  return result;
}

在这里,C# 和 Java 编译器都没有问题 - 不会抛出有关可能从 null 对象访问 A 的警告,因为它们发现之前立即完成了 null 检查。但是,如果我将验证代码提取/重构为单独的方法,C# 将失去查看它的能力:

public double DoSomething(MyClass obj)
{
  Validate(obj);
  
  var result = OtherMethodCall(obj.A); // C# throws warning that A is possibly accessed from a null object

  return result;
}

private void Validate(MyClass obj)
{
  if (obj is null) throw new ArgumentException("Object is null!");
}

Java 编译器仍然可以看到变量之前的路径(显然,对于 Java 代码,我们必须在方法签名中添加“抛出”声明),而 C# 似乎不再看到该路径。如果我在这个类中有 2 个或多个方法需要相同的验证代码,而这些方法不够复杂,不足以保证将单独的验证器类添加为依赖项,它会“迫使”我重复自己,以免在我的代码中出现任何警告,或者添加大量丑陋的预处理器或其他语句来抑制警告。谁能向我解释为什么这在 C# 中仍然是一个问题?在上面的链接中,他们说这是有意的,但他们计划在 C# 9.0 中修复其中一些情况,但我正在使用 10.0。

c# compiler-warnings
1个回答
1
投票

对于“为什么”的问题,它不太好回答。世界上的时间和资源都是有限的,而人们对于用语言表达什么内容却有着无限的想法。一定有一些的事情还没有实现。

在今天的 C# 中,您可以将验证和异常抛出代码提取到如下方法中:

using System.Diagnostics.CodeAnalysis;

double DoSomething(object? obj)
{
  if (!ValidateObject(obj)) ThrowCustomException(obj);
  
  // this shows that obj.ToString produces no warning 
  var result = Convert.ToDouble(obj.ToString());

  return result;
}

bool ValidateObject([NotNullWhen(true)] object? obj) => 
    // assuming you are doing a lot more validation in the real code
    obj is not null; 

[DoesNotReturn]
void ThrowCustomException(object? obj) =>
    // assuming that you are throwing a more "custom" exception in the real code
    // possibly making use of obj
    throw new NullReferenceException("obj is null!");

注意,验证和异常抛出需要放在单独的方法中,因为没有静态分析属性说“如果此参数为空,则该方法不返回”,以便您可以应用于您的版本

ValidateObject 
这也会引发异常。只有
[DoesNotReturn]
(无条件)和
[DoesNotReturnIf]
(以
bool
参数为条件)。

当方法返回 true 时,可以使用

[NotNullWhen]
告诉静态分析器参数不为空。这就是您得出上述解决方案的方式。

© www.soinside.com 2019 - 2024. All rights reserved.