考虑 C# 中的这个简单类(已启用可空性功能):
public class Error
{
public string Message = "...";
public static implicit operator bool(Error? err) => err is not null;
}
隐式布尔运算符允许我简化条件检查,如下所示:
var err = GetSomeError();
// scenario 1 (without implicit operator)
if (err is not null)
{
Console.WriteLine(err.Message);
}
// scenario 2 (with implicit operator)
if (err)
{
Console.WriteLine(err.Message); // <--- complains about nullability
}
然而,在场景 2 中,编译器不明白
err
永远不会出现 null
,尽管该隐式运算符的唯一目的是检查可空性,因此执行只会在以下情况下进入该 if 语句块: err is not null
。然而编译器无法识别这一点并抱怨,迫使我使用 bang 运算符:err!.Message
。 Bang 运算符并不是最糟糕的解决方案,但是,在代码库寿命足够长以进行几轮重构之后,我突然看到冗余的 bang 运算符,如果不是这个问题,这些运算符就不会存在,乍一看这还不错,但是,存在 bang 运算符混淆可为空区域的风险(重构改变了代码逻辑)。
有什么办法告诉编译器这一点吗?也许通过一些方法/类属性等?
[NotNullWhen(true)]
标记参数,就好像转换运算符是常规方法一样。
public static implicit operator bool([NotNullWhen(true)] Error? err) => err is not null;
编译器知道,当您执行
if(err)
时,您只是调用以 err
作为参数的转换运算符,并按预期分析可空性。