承上文 在 C# 中 Nullable Reference Types 使用属性AllowNull
继续探讨...
使用属性 NotNullWhen
假设我们有一个方法检查变数是否为 null。根据此检查的结果,该方法返回 bool 类型的值。
示例:
bool CheckNotNull(object? obj){ return obj != null;}
使用此方法:
public void Foo(object? obj1){ object obj2 = new object(); if (CheckNotNull(obj1)) obj2 = obj1;}
编译器将对上面的程式码发出警告:
警告讯息如下:
警告CS8600正在将 Null 常值或可能的 Null 值转换为不可为 Null 的型别。
但这段程式码NULL情况是不可能发生的,因为已经先检查确保不为空。问题是编译器无法理解这个情况,所以我们必须帮助它。
我们可以加入属性 NotNullWhen 来更改 CheckNotNull() 的签名:
bool CheckNotNull([NotNullWhen(true)]object? obj)
此属性将将参数的 Null 状态与 检查方法的回传值 相关联。
用来向编译器“解释”,如果方法返回 true,则该参数 obj 具有值非空。
这个NotNullWhen 属性还有一些特性如下:
若使用out修饰符
bool GetValidOrDefaultName([NotNullWhen(true)] out string? validOrDefaultName, string name){ if (name == null) { validOrDefaultName = name; return true; } else { validOrDefaultName = "defaultName"; return false; }}
编译器将对上面的程式码发出警告:
警告讯息如下:
警告CS8762参数 'validOrDefaultName' 在以 'true' 结束时必须具有非 Null 值。
这里警告非常合理,因为你用了NotNullWhen属性向编译器“解释”,
如果方法返回 true,则该参数 validOrDefaultName 具有值非空。
但在此段程式码中,当 validOrDefaultName 为 null 时,该方法返回 true。
除非你在条件中使用了 “!=” 而不是 “==” 运算符
若使用ref修饰符
bool SetDefaultIfNotValid([NotNullWhen(true)] ref string? name){ if (name == null) return true; name = "defaultName"; return false;}
编译器将对上面的程式码发出警告:
警告讯息如下:
警告CS8762参数 'name' 在以 'true' 结束时必须具有非 Null 值。
与前面的例子类似,这里警告非常合理,因为你用了NotNullWhen属性向编译器“解释”,
如果方法返回 true,则该参数 name 具有值非空。
因为你使用了 '==' 而不是 '!=' 运算符。
若不使用修饰符
bool CheckingForNull([NotNullWhen(true)] string? name){ if (name == null) return true; Console.WriteLine("name is null"); return false;}
这里的情况与之前的案例类似。按照前面例子的逻辑,这里应该也发出警告讯息:
Parameter 'name' must have a non-null value when exiting with 'true'。
但是,没有警告。
微软这样的逻辑其实很怪。 WHY???
什么原因造成的? 不好说~
也许这里就是所谓一些不显而易见的地方
了解更多:NotNullWhenAttribute Class
下一篇
在 C# 中 Nullable Reference Types 使用属性NotNullIfNotNull