noseratio
noseratio

Reputation: 61736

Non-nullable fields initialized inside a method called from the constructor

I have some non-nullable fields which I want to initialize inside a helper methods, called from a constructor, to reduce the clutter inside the constructor:

private FlowLayoutPanel _flowPanel;
private ComboBox _printersComboBox;
//...

public PrintSettingsView(IServiceProvider serviceProvider, IPrintSettings printSettings)
{
    InitializeComponent();
    PostInitializeComponent(); // this is where _flowPanel etc get initialized
    // ...
}

How do I avoid warnings like Non-nullable field '_flowPanel' must contain a non-null value when exiting constructor. Consider declaring the field as nullable?

The best idea I've come up with so far:

public static void Assert([DoesNotReturnIf(false)] bool condition)
{
  if (!condition) throw new InvalidOperationException();
}

public PrintSettingsView(IServiceProvider serviceProvider, IPrintSettings printSettings)
{
    InitializeComponent();
    PostInitializeComponent();

    Assert(_flowPanel != null);
    Assert(_printersComboBox != null);
    //...
}

It's still getting messy when there's a lot of fields. Is there anything better than this?

It's a .NET 6 project, so I could use the latest and the greatest.

enter image description here

Upvotes: 17

Views: 3222

Answers (4)

Drew Noakes
Drew Noakes

Reputation: 311245

Another option is to declare the fields as:

private FlowLayoutPanel _flowPanel = null!;
private ComboBox _printersComboBox = null!;

This forces the compiler to consider these fields as initialized, and the ! suppresses warnings that the value is null yet the field is not nullable.

Note that adding the null assignment does not change the generated code. There is no run-time impact, only design-time.

Upvotes: 10

Rikki Gibson
Rikki Gibson

Reputation: 4347

You have a few options:

  1. Use [MemberNotNull] on the helper methods. This is a bit verbose but it should work. See https://stackoverflow.com/a/64958374/2855742.
  2. Return values from your helper methods (maybe tuples?) and deconstruct-assign right into the fields you want to initialize.

Upvotes: 16

DamienG
DamienG

Reputation: 6665

Could you have PostInitializeComponent return the FlowPanel?

then

public PrintSettingsView(IServiceProvider serviceProvider, IPrintSettings printSettings)
{
    InitializeComponent();
   _flowPanel = PostInitializeComponent();
    // ...
}

If PostInitializeComponent does a bunch of work maybe extract out the part that builds FlowPanel and have that return it and assigned.

Upvotes: 2

UnexpectedSemicolon
UnexpectedSemicolon

Reputation: 81

what about defining them as nullable like:

FlowLayoutPanel? _flowPanel;

Upvotes: 0

Related Questions