Har*_*rry 11 c# nullable c#-10.0
考虑一个例子:
class Test {
string S { get; set; }
public Test() {
Init();
}
private void Init() {
S = "hello";
}
}
Run Code Online (Sandbox Code Playgroud)
使用可空 C# 项目功能,此示例将触发编译器警告:
警告 CS8618 退出构造函数时,不可为 null 的属性“S”必须包含非 null 值。考虑将该属性声明为可为空。
但是,退出构造函数时,该属性确实包含非空值,只是不是直接在构造函数中设置,而是在从构造函数无条件调用的方法中间接设置。
这个例子清楚地表明该属性不可能为S空。Test创建类的实例时,Init()将无条件调用该方法,因此该S属性始终设置为“hello”。
当然,这个警告可以在代码中被抑制,但这看起来很丑陋。这是告诉编译器我确实S在其他地方将该属性设置为非空值的更好方法吗?
顺便说一句,如果您真的想知道为什么要在构造函数中间接设置值,让我们考虑一下类型D的另一个派生属性Derived。要创建字符串的实例,Derived必须首先解析字符串,我们不想每次读取属性时都解析字符串D。
因此,更实际的代码看起来更像是这样的:
class Test {
public string S {
get => _S;
set => D = new Derived(_S = value);
}
public Derived D { get; private set; }
public Test(string s) => D = new Derived(_S = s);
private string _S;
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,退出构造函数时,S和都D被设置为非空值。但该代码仍然会触发编译器警告 CS8618。
Luk*_* Vo 19
用于MemberNotNullAttribute标记你的函数:
using System.Diagnostics.CodeAnalysis;
class Test
{
string S { get; set; }
public Test()
{
Init();
}
[MemberNotNull(nameof(S))]
private void Init()
{
S = "hello";
}
}
Run Code Online (Sandbox Code Playgroud)
如果您没有在 中初始化 S,编译器现在会抱怨Init:
更多场景请参阅本文:空状态静态分析的属性