Here are some of the reasons why nullable reference types are less than ideal:
- Invoking a member on a null value will issue a System.NullReferenceException exception, and every invocation that results in a System.NullReferenceException in production code is a bug. Unfortunately, however, with nullable reference types we “fall in” to doing the wrong thing rather than the right thing. The “fall in” action is to invoke a reference type without checking for null.
- There’s an inconsistency between reference types and value types (following the introduction of Nullable<T>) in that value types are nullable when decorated with “?” (for example, int? number); otherwise, they default to non-nullable. In contrast, reference types are nullable by default. This is “normal” to those of us who have been programming in C# for a long time, but if we could do it all over, we’d want the default for reference types to be non-nullable and the addition of a “?” to be an explicit way to allow nulls.
- It’s not possible to run static flow analysis to check all paths regarding whether a value will be null before dereferencing it, or not. Consider, for example, if there were unmanaged code invocations, multi-threading, or null assignment/replacement based on runtime conditions. (Not to mention whether analysis would include checking of all library APIs that are invoked.)
- There’s no reasonable syntax to indicate that a reference type value of null is invalid for a particular declaration.
- There’s no way to decorate parameters to not allow null.