`null!` in C#? What is "null-forgiving" operator?
Explore non-nullable reference types in C#
Detour
What are the Non-Nullable Reference types?
So far all the reference types in C# have always been nullable (before C# 8.0 ). The option to have non-nullable reference type was not there. On the other-hand the value types have always been nullable(? ) and non-nullable(by default ).
This resulted in a lot of null checking repetitive code (try to think how many lines of code you have written just for null check!).
So, In C# 8.0 Microsoft added support for non-nullable reference types. But they implemented this by changing the current implementation. So now, reference types are by default non-nullable just like value types.
To make them nullable they need to be marked with ?
or wrapped in Nullable<T>
.
It gives freedom to mark any reference type as optional or mandatory.
On the left is what we would have written. On the right is how it does not require that null check.
Note: This feature is added in C# 8.0. It needs to be enabled in existing codebase because it introduces breaking changes. Also if the non-nullable identifier is assigned a null value or not assigned at all then it will only show warning (CS8618) not error. To show it as an error, some configurations need to be set in project file.
Nullable reference type example:
Above code does not result in any warnings as it is expected to have null value.
Non-nullable reference type example:
Note: Here Value
can be of any reference type for e.g. List, Action, NonNullableExample, etc.
Since the
Value
(of type string) is now a non-nullable type and there is no constructor assigning a value to that property, the compiler would show a warning that theValue
has not been initialised.
This warning helps identifying code that may generate NullReferenceException
if used without null check.
Coming to the main point
To suppresses the CS8618 warning the null-forgiving operator or null!
is used:
Note: Here null!
tells the compiler that I know this property should not be null but I am assigning it anyway and I promise that I will assign non-null value to it before using it.
The thing to note here is that normally null-forgiving operator should be avoided. Because it would be used in code without null check assuming that it always has some value. It can easily result in run-time exception. It shows flaw in design, consider marking that identifier as nullable if necessary.
But there can be some edge cases when we want to intensionally assign null value to a non-nullable type. Below is list of such cases:
- Unit testing: Set null to nullable to type to check program behaviour.
- Unit testing: Initialising
sut
and dependencies in Setup method instead of constructor. - When it requires deferred field initialisation.
- Legacy code migration. The
null!
should be removed in further refactoring though.
Conclusion: 99% of cases don't require
null!
so don't use it without valid reason.