What is the difference between a nullable string (string?) and a string initiated to a forgiven null (string s = null!)
One is correct. The other is really dumb.
Are there any situations where you would want to use one over the other?
In this author's opinion, no.
...but there are plenty of cases where !
is needed due to current limitations of C#'s nullable reference types feature, including Expression<>
, ValueTuple
, Linq, but property initialization is not one of them: if a property is "never null
" then the property must be assigned in the constructor or in an initializer (and since C# 11: with the required
modifier), therefore using = null!
to initialize a property is unnecessary and incorrect.
If you do have legacy code that cannot use nullable reference types, or code that uses some runtime sytem for intialization (such as DbSet<T>
properties in DbContext
in Entity Framework) then use scoped #pragma
and #nullable
directives to suppress warnings instead of !
and always add an explanatory comment justifying why so that the next poor colleague of yours won't have to struggle unnecessarily to understand what's going on.
Are they functionally equivalent?
No.
A class member declaration of public string Foo { get; set; }
is a contract that says "Foo
will never be null
: it will always be safe to dereference the String
-reference this property's getter returns, and it is illegal to pass a null
reference into the property setter."
Skirting rules with = null!
is like saying "This property will never be null
, unless it is. Have fun.". Don't do it.
Another reason not to do = null!
with DbContext
's DbSet<T>
properties is because reference-type fields are always initialized to null
anyway before being populated by DbContext
's constructor (e.g. EF6 uses its magical DbContext.DiscoverAndInitializeSets()
method), so explicitly initializing a reference-type property to null
when it's going to be set to a non-null
object-reference by the superclass ctor is redundant.