我在使用 Visual Studio 2022 (C# .NET 6.0) 时遇到问题,即使执行空检查后,它也会发出 CS8602 警告(“取消引用可能为空的引用”)。这是代码片段:
public interface IParameter
{
public string? Input { get; set; }
}
public static class FalseWarningTest
{
public static string[] SeeTheFalseWarning(this IParameter parameter)
{
if (string.IsNullOrWhiteSpace(parameter.Input))
{
throw new InvalidOperationException("Input must have value");
}
return parameter.Input.Split(':');
}
}
尽管在使用之前检查了
parameter.Input
上的 null 或空格,Visual Studio 仍然警告它在使用时可能为 null。
但是,当我明确检查 null (应该是redundant)时,警告消失了:
public static string[] SeeTheFalseWarning(this IParameter parameter)
{
if (parameter.Input == null || string.IsNullOrWhiteSpace(parameter.Input))
{
throw new InvalidOperationException("Input must have value");
}
return parameter.Input.Split(':');
}
据我了解,CS8602 警告是一项防止空引用异常的功能。但是,在这种情况下这是一个错误吗,因为在使用
parameter.Input
之前执行了空和空格检查,还是我误解了什么?
是的,你误解了一些东西。人们可以用 C# 做一些你意想不到的邪恶事情:)
您正在检查 getter 而不是局部变量。 getter 不需要在两次不同的调用中返回相同的值。让我们构建一个消除“空检查”的类:
public class DestroyYourNullCheck : IParameter
{
private bool checked = false;
public string? Input
{
get
{
if(checked) return null; // boom
checked = true;
return "NonNullString";
}
set {}
}
}
哎呀..但它不是空的。确实,你检查的时候不是这样。就在那之后...
为了让编译器“信任”空检查,它必须是在检查和使用之间无法更改的东西。最明显的是局部变量,因为很容易评估它是否发生变化。 所以你的支票应该是这样的:
public static string[] SeeTheFalseWarning(this IParameter parameter)
{
var input = parameter.Input; // local vairable, getter evaluated exactly once
// local variable null checked
if (string.IsNullOrWhiteSpace(input))
{
throw new InvalidOperationException("Input must have value");
}
// compiler knows for sure local variable cannot possibly have changed since the null check:
return input.Split(':');
}