How can we use non-nullable reference types in combination with the Options pattern?
Let's say we have an options model named MyOptions
.
The services requiring those options are getting IOptions<MyOptions> options
injected into the constructor.
Configuring the options happens on the IServiceCollection
like this:
services
.AddOptions<MyOptions>()
.Configure(options =>
{
options.Name = "ABC";
});
Now, the problem is in the definition of MyOptions
:
public sealed class MyOptions
{
public string Name { get; set; }
}
which generates the warning:
CS8618 Non-nullable property 'Name' is uninitialized. Consider declaring the property as nullable.
- We don't want to make
Name
nullable as then we need to place traditional null checks everywhere (which is against the purpose of non-nullable reference types) - We can't create a constructor to enforce the
MyOptions
class to be created with a non-nullablename
value as theConfigure
method construct the options instance for us - We can't use the null-forgiving operator trick (
public string name { get; set; } = null!;
) as then we can't ensure theName
property is set and we can end up with anull
in theName
property where this would not be expected (inside the services)
Any other option I forgot to consider?
It seems, that you have two possible options here. First one is to initialize an
Options
properties using empty string (instead ofnull
value) to avoidnull
checksSecond one is to make all of the properties a nullable ones and decorate them using
DisallowNull
precondition andNotNull
postcondition.DisallowNull
means that nullable input argument should never be null,NotNull
- a nullable return value will never be null. But these attributes only affect nullable analysis for the callers of members that are annotated with them. So, you are indicating that your property can never returnnull
or be set tonull
, despite nullable declarationand the usage example
But the next example doesn't show a warning, because nullable analysis doesn't work properly in object initializers yet, see GitHub issue 40127 in Roslyn repository.
(Edit: This issue was fixed already, shipped in version 16.5 in March, 2020 and should go away after updating a VS to the latest version.)
The same picture for property getter, the following sample doesn't show any warnings, because you indicated that nullable return type can't be
null
but attempting to set a
null
value and get it generates a warning (compiler is smart enough to detect such scenarios)If the expected behavior of the property is that it may initially contain null but should never be set to null, then try using DisallowNullAttribute.