“Non-nullable field is uninitialized”的编译器错误,即使它已在 InitializeComponents 函数中初始化

Posted

技术标签:

【中文标题】“Non-nullable field is uninitialized”的编译器错误,即使它已在 InitializeComponents 函数中初始化【英文标题】:Compiler error of "Non-nullable field is uninitialized" even though it was initialized in InitializeComponents function 【发布时间】:2019-08-15 16:45:50 【问题描述】:

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

class SomeClass : Form 
  Button b;

  SomeClass() 
    InitializeComponents();
  

  SomeClass(Container x) 
    InitializeComponents();
  

  void InitializeComponents() 
    b = new Button();
  

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

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

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

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

尤瓦尔

【问题讨论】:

【参考方案1】:

根据preview docs:

问:为什么会针对已初始化的字段报告警告 间接由构造函数,还是在构造函数之外?

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

因此,现在没有办法在不将该赋值直接移入构造函数(或在声明它的行上赋值)的情况下实现您想要的。

【讨论】:

因为您已经回答了这个问题,所以添加了一些属性,例如[MaybeNull]。您知道是否添加了任何内容来告诉编译器该字段始终被初始化? 我不知道这样的事情@andre_ss6。【参考方案2】:

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

class SomeClass : Form 
  private readonly Button b;

  public SomeClass() 
    b = new Button();
  

  public SomeClass(Container x): this() 
    // Something else...
  

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

【讨论】:

以上是关于“Non-nullable field is uninitialized”的编译器错误,即使它已在 InitializeComponents 函数中初始化的主要内容,如果未能解决你的问题,请参考以下文章