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
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.
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...)
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.
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.
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With