Skip to main content

.NET 9 upgrade–notnull constraint

With the Christmas Holidays after us, I finally got some time to start upgrading some older .NET Core applications to .NET 9. First thing I noticed after upgrading is that I got some new warnings related to the ‘notnull’ constraint.

The ‘notnull’ constraint was introduced as part of the nullable reference types feature in C#.  The goal of nullable reference types was to solve the ‘million dollar mistake’ and help you to prevent common issue of null reference exceptions. They allow  to explicitly state whether a reference type variable can be null or not, helping to catch potential null dereferences at compile time.

The feature is in fact a combination of multiple elements all with the goal of avoiding unexpected null reference exceptions:

  • Nullable and Non-Nullable Reference Types:

    • Non-Nullable: If you declare a reference type without the ? suffix (e.g., string name), it is considered non-nullable. The compiler issues warnings if you try to assign a null value to it.

    • Nullable: If you declare a reference type with the ? suffix (e.g., string? name), it can hold a null value. The compiler warns you when you might dereference it without a null check.

  • Null-State Analysis: The compiler tracks the null-state of each variable, which can be either not-null or maybe-null. It issues warnings if there's a possibility of a null dereference.

  • Annotations and Attributes: You can use various attributes (like [NotNullWhen(false)]) and annotations to give the compiler more information about the nullability of parameters and return values in methods.

  • As part of this feature a new generic constraint was introduced, the ‘notnull’ constraint. This guarantees that the provided type is a non-nullable type. This can either be a non-nullable reference type or a non-nullable value type.

    Remark: As this feature was introduced already in C# 8.0, I think it is just a coincidence I noticed it only after upgrading to .NET 9. One extra reason to enable the ‘Treat warnings as errors’ flag…

    I got 2 places where I got this warning:

    ModuleExtensions.cs(83,137,83,144): warning CS8714: The type 'T' cannot be used as type parameter 'TKey' in the generic type or method 'Dictionary<TKey, TValue>'. Nullability of type argument 'T' doesn't match 'notnull' constraint.

    NoOpLogger.cs(15,24,15,34): warning CS8633: Nullability in constraints for type parameter 'TState' of method 'NoOpLogger.BeginScope<TState>(TState)' doesn't match the constraints for type parameter 'TState' of interface method 'ILogger.BeginScope<TState>(TState)'. Consider using an explicit interface implementation instead.

    Here is each time the original code and the fix:

    Original code:

    private static void SortByDependenciesVisit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted, Dictionary<T, bool> visited)
    view raw Original.cs hosted with ❤ by GitHub

    Fix:

    private static void SortByDependenciesVisit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted, Dictionary<T, bool> visited) where T:notnull
    view raw Fix.cs hosted with ❤ by GitHub

    Original code:

    internal class NoOpLogger : ILogger
    {
    private static NoOpDisposable NoOpDisposable = new NoOpDisposable();
    public IDisposable BeginScope<TState>(TState state) => NoOpDisposable;
    public bool IsEnabled(LogLevel logLevel) => false;
    }
    view raw Original.cs hosted with ❤ by GitHub

    Fix:

    internal class NoOpLogger : ILogger
    {
    private static NoOpDisposable NoOpDisposable = new NoOpDisposable();
    public IDisposable BeginScope<TState>(TState state) where TState:notnull => NoOpDisposable;
    public bool IsEnabled(LogLevel logLevel) => false;
    }
    view raw Fix.cs hosted with ❤ by GitHub

    More information

    Nullable reference types - C# | Microsoft Learn

    The history of C# | Microsoft Learn

    Popular posts from this blog

    Kubernetes–Limit your environmental impact

    Reducing the carbon footprint and CO2 emission of our (cloud) workloads, is a responsibility of all of us. If you are running a Kubernetes cluster, have a look at Kube-Green . kube-green is a simple Kubernetes operator that automatically shuts down (some of) your pods when you don't need them. A single pod produces about 11 Kg CO2eq per year( here the calculation). Reason enough to give it a try! Installing kube-green in your cluster The easiest way to install the operator in your cluster is through kubectl. We first need to install a cert-manager: kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.5/cert-manager.yaml Remark: Wait a minute before you continue as it can take some time before the cert-manager is up & running inside your cluster. Now we can install the kube-green operator: kubectl apply -f https://github.com/kube-green/kube-green/releases/latest/download/kube-green.yaml Now in the namespace where we want t...

    Azure DevOps/ GitHub emoji

    I’m really bad at remembering emoji’s. So here is cheat sheet with all emoji’s that can be used in tools that support the github emoji markdown markup: All credits go to rcaviers who created this list.

    .NET 9 - Goodbye sln!

    Although the csproj file evolved and simplified a lot over time, the Visual Studio solution file (.sln) remained an ugly file format full of magic GUIDs. With the latest .NET 9 SDK(9.0.200), we finally got an alternative; a new XML-based solution file(.slnx) got introduced in preview. So say goodbye to this ugly sln file: And meet his better looking slnx brother instead: To use this feature we first have to enable it: Go to Tools -> Options -> Environment -> Preview Features Check the checkbox next to Use Solution File Persistence Model Now we can migrate an existing sln file to slnx using the following command: dotnet sln migrate AICalculator.sln .slnx file D:\Projects\Test\AICalculator\AICalculator.slnx generated. Or create a new Visual Studio solution using the slnx format: dotnet new sln --format slnx The template "Solution File" was created successfully. The new format is not yet recognized by VSCode but it does work in Jetbr...