Skip to content
Ian Griffiths By Ian Griffiths Technical Fellow I
C# 8.0 nullable references: NotNull

So far in this sub-series on attributes for getting better results from C# 8's nullable references feature I've described the AllowNull and DisallowNull attributes.

Now it's NotNull's turn.

The Introduction to Rx.NET 2nd Edition (2024) Book, by Ian Griffiths & Lee Campbell, is now available to download for FREE.

As with all of these attributes, this enables us to describe our intent in more detail so that the compiler can find more null-related programming errors without producing spurious warnings.

This particular post is concerned with a scenario where the successful execution of a method implies that we can now be certain that something isn't null, and we'd like the compiler to know that.

Whereas DisallowNull made a statement about what's acceptable for a method's or property's input, NotNull tells the compiler about how things will be once a method returns.

Programming C# 10 Book, by Ian Griffiths, published by O'Reilly Media, is now available to buy.

You might have wondered why I didn't just put that in the obvious way, by saying that NotNull makes a statement about outputs. Well that's one way to use it, but as you'll soon see, it's not the only way.

Nullable in, non-nullable out for ref arguments

Just as a property may want to accept a null input while asserting that it will never provide a null output, the same may be true for a method with a ref parameter.

You can annotate ref parameters that have a nullable reference type with a NotNull attribute to indicate that although a null input is acceptable, the compiler can presume that the variable will not be null once the method returns.

This shows how the attribute is used in the .NET class library's LazyInitializer.EnsureInitialized method:

public static T EnsureInitialized<T>([NotNull] ref T? target) where T : class

Just in case you've not come across this bit of the .NET class library before, this method enables you to delay construction of an object until you need it, a practice that can help improve an application's startup time by not attempting to run code until the application knows it's necessary.

So it is a fundamental aspect of the design of this method that the reference passed to this method (typically a reference to a field) will be null the first time it is called for that field, but that the method guarantees that the field will not be null by the time the method returns.

Revealing information about an input

So why did I used slightly convoluted language in my earlier description? There's a slightly less obvious use of this attribute. You can apply it to a non-out, non-ref parameter:

static void ThrowIfNull([NotNull] string? x)
    if (x == null)
        throw new ArgumentNullException();

This asserts that if the method returns, null analysis can safely conclude that the expression passed as an argument to the method was not null. It is valid to pass in a null argument, it's just that the method won't return if that happens—it throws an exception instead.

So this is not a statement about the method's output. It is a statement about the method's inputs, and more specifically it tells the compiler something that it can infer about the input once the method returns.

The critical point about this way of using NotNull is that there are some methods that will sometimes choose not to return.

This attribute is particularly useful if you are in the habit of writing helper methods that validate arguments and throw exceptions if they are invalid in some way.

If you have a common helper for rejecting null arguments, applying this attribute to its input means the compiler will correctly determine that the variable passed as an argument is non-null (even if it is declared as having a nullable type) for any code that comes after you checked the argument.

Ian Griffiths

Technical Fellow I

Ian Griffiths

Ian has worked in various aspects of computing, including computer networking, embedded real-time systems, broadcast television systems, medical imaging, and all forms of cloud computing. Ian is a Technical Fellow at endjin, and Microsoft MVP in Developer Technologies. He is the author of O'Reilly's Programming C# 10.0, and has written Pluralsight courses on WPF (and here) and the TPL. He's a maintainer of Reactive Extensions for .NET, Reaqtor, and endjin's 50+ open source projects. Technology brings him joy.