“不可为空字段未初始化”的编译器错误,即使它是在 InitializeComponents 函数中初始化的

Yuv*_*avy 10 c# winforms c#-8.0 nullable-reference-types

在 WinForms 中,常见的初始化函数是初始化引用变量(例如)

class SomeClass : Form {
  Button b;

  SomeClass() {
    InitializeComponents();
  }

  SomeClass(Container x) {
    InitializeComponents();
  }

  void InitializeComponents() {
    b = new Button();
  }
}
Run Code Online (Sandbox Code Playgroud)

如您所见, b 始终初始化为非空值。但是,C# 8 仍然会抱怨 SomeClass() 没有初始化不可为 null 的值 b。

当然我可以将 b 标记为可空(按钮?b)但是,现在我会在每次使用 b 时收到警告,因为未检查可空性(它不能为空...)

解决此问题的最佳方法是什么。是否有可用于将 InitializeComponent 标记为始终由构造函数调用的属性?

请注意,这是 WinForms 中非常常见的模式(每个组件...)

尤瓦尔

mjw*_*lls 9

根据预览文档

问:为什么会为由构造函数间接初始化或在构造函数外部初始化的字段报告警告?

答:编译器仅识别在当前构造函数中显式分配的字段,并对声明为不可为空的其他字段发出警告。这忽略了可以初始化字段的其他方式,例如工厂方法、辅助方法、属性设置器和对象初始值设定项。我们将研究如何识别常见的初始化模式以避免不必要的警告。

那么,有没有办法,现在达到你想要的东西,而不用直接移动该分配到构造函数(或声明该行指定的话)。


Adr*_*tti 5

对于您非常具体的示例,解决方案是合并InitializeComponent()到默认构造函数中并从第二个构造函数中调用它。

class SomeClass : Form {
  private readonly Button b;

  public SomeClass() {
    b = new Button();
  }

  public SomeClass(Container x): this() {
    // Something else...
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这是一个众所周知的当前限制,而且,所有设计器生成的代码都不会遵循这种模式,那么您可能需要在#nullable disable这里和那里放置一些(或其他指令之一,视情况而定)。