Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler error of "Non-nullable field is uninitialized" even though it was initialized in InitializeComponents function

In WinForms it is common that a common initialization function is initializing reference variables (for example)

class SomeClass : Form {
  Button b;

  SomeClass() {
    InitializeComponents();
  }

  SomeClass(Container x) {
    InitializeComponents();
  }

  void InitializeComponents() {
    b = new Button();
  }
}

As you can see b is always initialized to a non-null value. However, C# 8 will still complain that SomeClass() does not initialize non-nullable value b.

Of course I could mark b as nullable (Button? b) however, now I will get a warning on every usage of b, since nullability is not checked (it cannot be null...)

What is the best way to resolve this. Is there an attribute that can be used to flag InitializeComponent as being always called by constructor?

Please note, this is a very common pattern in WinForms (every component...)

Yuval

like image 893
Yuval Rakavy Avatar asked Mar 25 '19 12:03

Yuval Rakavy


People also ask

What is non-nullable field in C++?

Non-nullable field is uninitialized. Consider declaring as nullable. Nullability of reference types in value doesn’t match target type. Argument cannot be used for parameter due to differences in the nullability of reference types. Nullability of reference types in return type doesn’t match the target delegate.

Does SomeClass() initialize non-nullable values?

As you can see b is always initialized to a non-null value. However, C# 8 will still complain that SomeClass () does not initialize non-nullable value b. Of course I could mark b as nullable (Button? b) however, now I will get a warning on every usage of b, since nullability is not checked (it cannot be null...)

Can a nullable value type be used as a parameter?

Nullable value type may be null. The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn’t match constraint type. The annotation for nullable reference types should only be used in code within a ‘#nullable’ annotations context.

What does [-Wuninitialized] mean in C++?

This can occur when a path through the code bypasses the setting of the variable, or when the variable was never set. The [-Wuninitialized] warning is enabled by specifying the -Wall compiler option.


2 Answers

As per the preview docs:

Q: Why are warnings reported for fields that are initialized indirectly by the constructor, or outside the constructor?

A: The compiler recognizes fields assigned explicitly in the current constructor only, and warns for other fields declared as non-nullable. That ignores other ways fields may be initialized such as factory methods, helper methods, property setters, and object initializers. We will investigate recognizing common initialization patterns to avoid unnecessary warnings.

So, there is no way, right now to achieve what you want without moving that assignment directly into the constructor (or assigning it on the line that declares it).

like image 155
mjwills Avatar answered Oct 18 '22 21:10

mjwills


For your very specific example the solution is to merge InitializeComponent() into the default constructor and to invoke it from the second one.

class SomeClass : Form {
  private readonly Button b;

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

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

Unfortunately this is a well-known current limitation and, moreover, all the designer generated code won't follow this pattern then you may need to put some #nullable disable (or one of the other directives, as appropriate) here and there.

like image 5
Adriano Repetti Avatar answered Oct 18 '22 19:10

Adriano Repetti