【发布时间】:2020-03-23 11:22:04
【问题描述】:
我想知道如何在 C# 中使用 late-initialized 类字段和 可为空的引用类型。 想象一下下面的类:
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
}
}
上面的代码非常简化。我的真实类使用了更多字段,例如doc,并且还有一些带有一些参数的构造函数。
使用上面的代码,我在构造函数上得到一个编译器警告,doc 没有初始化,这是正确的。我可以通过将doc 的类型设置为PdfDoc? 来解决这个问题,但是我必须在任何使用它的地方都使用?. 或!.,这很讨厌。
我也可以将doc 作为参数传递给每个方法,但请记住,我有一些这样的字段,这违反了我眼中的干净代码原则。
我正在寻找一种方法来告诉编译器,我将在使用之前初始化doc(实际上我这样做了,调用者不可能得到空引用异常!)。我认为 Kotlin 有 lateinit 修饰符正是为了这个目的。
你会如何在“干净”的 C# 代码中解决这个问题?
【问题讨论】:
-
您尝试初始化它吗?像这样:
private PdfDoc doc = null; -
类似问题,只是从构造函数移到声明:“无法将空字面量转换为不可为空的引用类型。”
-
那么可能是某种
private PdfDoc doc = PdfDoc.Empty;,其中PdfDoc.Empty是static readonly字段? -
不,不是。在我看来,
null与“未初始化”不同。浏览我的代码,在初始化之前不可能读取pdfDoc变量。我没有违反了非空规则,编译器似乎无法证明这一点(还)。 -
使用反射可以破坏各种东西,甚至将
null值放入不可为空的类型中。代码分析只能处理常规的控制流,这很好。
标签: c# nullable-reference-types lateinit