Upgrading to nullability in C#
Published by marco on
The Talk − Bringing C# nullability into existing code by Maarten Balliauw is a 66-slide deck that I summarize as follows:
- The C# nullability feature is for build- and design-time. It does not enforce anything at runtime. That means that you still have to check parameters for
null
. - The C# nullability feature is available to solutions working with .NET Framework and .NET.
- For .NET Framework, you have to explicitly set the
<LanguageVersion>
to8.0
(however, there are a bunch of cons associated with doing this, as the runtime library itself is not annotated).[1] - The presentation shows how to enable and disable for the whole solution, project, or an individual code region.
- For new solutions, enable at the solution level.
- For small solutions, enable at the solution level and just work through it.
- For large solutions, enable project-by-project or file-by-file—or even class-by-class.
- “Start at the center and work outwards.”
- While
?
suffices in most cases, consider annotations to improve your own APIs - Consider redesigning APIs that return
null
(use thebool TryGet<T>(…, out T)
pattern or return a “null” object instead). - Avoid allowing
null
parameters (these force a decision on the implementation that is often better handled by the caller). - Don’t use
!
except temporarily - Don’t use suppression except temporarily
- Start with types that aren’t depended on a lot. Those are easy.
- Take types with lots of dependents one-by-one.
For more information, see C# 8.0 nullable references: supporting older runtimes by Ian Griffiths, published in July of 2021. Also, the article Consider using C# 8 with the .NET Framework cites from Building C# 8.0 by Mads Torgersen. Both of those articles are from 2018.
“using C# 8.0 is only supported on platforms that implement .NET Standard 2.1”
.NET Framework doesn’t implement .NET Standard 2.1
However, the StackOverflow post Does C# 8 support the .NET Framework? goes into some detail about which features of C# 8.0 could be supported under .NET Framework. That post notes that syntax-only changes will continue to work, which makes sense. As long as you use a newer compiler that understands the syntax, the lowered code and subsequent generated IL will be compatible with the .NET Framework runtime. That’s what syntax-only means: no new functionality was required in the runtime in order to support the generated output.
- Static local functions
- Using declarations
- Null-coalescing assignment
- Readonly members
- Disposable ref structs
- Positional patterns
- Tuple patterns
- Switch expressions
- Nullable reference types are also supported, but the new nullable attributes required to design the more complex nullable use cases are not. However, according to C# 8.0 nullable references: supporting older runtimes, there’s a Nullable Nuget package. Be aware, though, that the .NET Framework is not itself annotated, so you will probably see spurious warnings when the compiler can’t tell that a result can never be null.
That’s a lot of features, actually!
The StackOverflow post linked above lists them quite well, and C# 8.0 and .NET Standard 2.0 − Doing Unsupported Things has some more information about which level of change each C# 8.0 feature requires.
That said,
↩“The C# 8/.NET Framework combination is not officially supported by Microsoft. It is, they say, for experts only.”