2

What is the difference between a nullable string (string?) and a string initiated to a forgiven null (string s = null!)

public string? nullableString {get;set;} = null;
public string forgiveString {get;set;} = null!

Are there any situations where you would want to use one over the other? Are they functionally equivalent?

SmashCode
  • 4,227
  • 8
  • 38
  • 56
  • https://stackoverflow.com/questions/67505347/non-nullable-property-must-contain-a-non-null-value-when-exiting-constructor-co/69685202#69685202 – Vivek Nuna Nov 19 '22 at 04:29

1 Answers1

4

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.

Dai
  • 141,631
  • 28
  • 261
  • 374
  • I wasn't even aware of the null forgiveness operator until I was working through the following MongoDB C# driver tutorial and the guy was using it and it confused the hell out of me : https://youtu.be/jJK9alBkzU0?t=577 – SmashCode Nov 19 '22 at 00:16
  • @SmashCode Without commenting on that particular video, I note that YouTube "coding" tutorials are not generally known for their quality or adherence to best-practices. (I'll make an exception for [Coding Train](https://www.youtube.com/channel/UCvjgXvBlbQiydffZU7m1_aw) - I wish I could be like him) – Dai Nov 19 '22 at 00:19
  • @Dai unfortunately Microsoft's own documentation promotes the `= null!;` pattern which is a shame. https://learn.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types – Aluan Haddad Nov 22 '22 at 00:16
  • 1
    @AluanHaddad I know - I should make a PR but `:effort:`. – Dai Nov 22 '22 at 00:17
  • 1
    You should. The pragma approach you suggest is so much better – Aluan Haddad Nov 22 '22 at 00:18