And*_*ndi 3 c# nullable-reference-types lateinit
我想知道如何在带有可为空引用类型的C# 中使用后期初始化的类字段。想象一下下面的类:
public class PdfCreator {
private PdfDoc doc;
public void Create(FileInfo outputFile) {
doc = new PdfWriter(outputFile);
Start();
}
public void Create(MemoryStream stream) {
doc = new PdfWriter(stream);
Start();
}
private void Start() {
Method1();
// ...
MethodN();
}
private void Method1() {
// Work with doc
}
// ...
private void MethodN() {
// Work with doc
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码非常简化。我真正的班级使用了更多的领域,比如doc,还有一些带有一些参数的构造函数。
使用上面的代码,我在构造函数上收到编译器警告,doc未初始化,这是正确的。我可以通过设置docto的类型来解决这个问题PdfDoc?,但是我必须使用?.或!.任何它的地方,这很糟糕。
我也可以doc作为参数传递给每个方法,但请记住,我有一些这样的字段,这违反了我眼中的干净代码原则。
我正在寻找一种方法来告诉编译器,我将doc在使用它之前进行初始化(实际上我这样做了,调用者不可能获得空引用异常!)。我认为 Kotlin 有lateinit专门用于此目的的修饰符。
您将如何在“干净”的 C# 代码中解决这个问题?
到目前为止,我找到的最佳解决方案是:
private PdfDoc doc = null!;
Run Code Online (Sandbox Code Playgroud)
这通过使用C# 8 中引入的null-forgiving 运算符删除了所有编译器警告。它允许您使用一个值,就好像它不为 null。因此,当您需要类似于 Kotlin 的“ lateinit ”的东西时,可以使用它的一种方式。与 Kotlin 的 lateinit 不同,它实际上会在此处初始化为 null,这将被编译器和运行时所允许。如果您稍后在不期望为 null 的地方使用此变量,您会得到 NullReferenceException,并且编译器不会警告您它可能为 null,因为它会认为它不为 null。Kotlin 的 lateinit 有一个微妙的区别,如果你在初始化之前访问了一个 lateinit 属性,它会抛出一个特殊的异常,清楚地标识正在访问的属性以及它没有的事实'