By switching the LangVersion to 8.0 and setting Nullable to enable in the csproj-file we are now benefiting from the nullable reference types introduced with the latest version of C#. By enabling this new feature all type members, input and output parameters are considered to be not-null. If some members or parameters, like string value can be null then we need to put a ? at the end of the type: string? value.

For most use cases putting a ? is enough but sometimes we need more control over when a parameter is null and when it isn't. To do so we can use one of the new attributes from the namespace System.Diagnostics.CodeAnalysis, some of them are NotNullWhen and NotNullIfNotNull.

Here is an example to make the benefits of one of the attributes more clear:

[return: NotNullIfNotNull("value")]
public static string? Reverse(this string? value)
{
   if (value == null)
      return null;

   return new String(Enumerable.Reverse(value).ToArray());
}

The NotNullIfNotNull states that if the parameter value is not null then the output will be not null as well. Thanks to the annotation we get a corresponding warning when trying to access a null reference.

string value1 = null;
var firstChar1 = value1.Reverse()[0]; // Warn: Dereference of a possibly null reference.

string value2 = "123";
var firstChar2 = value2.Reverse()[0]; // No warning

The problem is, this attributes are available in projects referencing .NET Standard 2.1 or .NET Core 3.0. So, having a class library targeting multiple frameworks like .NET Standard 2.0, .NET Standard 2.1 and .NET 4.8 we are kind of limited to the ? only, or so it seems.

The solution looks the same as with Jetbrains.Annotations, we copy the code of the required attributes into our project and make them internal:

#if !NETSTANDARD2_1

namespace System.Diagnostics.CodeAnalysis
{
   [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
   internal sealed class NotNullIfNotNullAttribute : Attribute
   {
      public string ParameterName { get; }

      public NotNullIfNotNullAttribute(string parameterName)
      {
         ParameterName = parameterName;
      }
   }
}
#endif

The null-checks are now available in projects targeting the "older" platforms as well.

Related Articles

.net
Strongly-typed Configuration for .NET Core - with full Dependency Injection support
Configuration is one of the most prominent cornerstones in software systems, and especially in distributed systems. And it has been a point for discussions in .NET for quite some time. In one of our projects we have built a solution that lets different applications in different…
Pawel Gerr
.net
.NET Abstractions - It's not just about testing!
With the introduction of .NET Core we got a framework that works not just on Windows, but on Linux and macOS as well. One of the best parts of .NET Core is that the APIs stayed almost the same compared to the old .NET, meaning developers can use their .NET skills to build cross…
Pawel Gerr
.net
.NET Core - Lowering the log level of 3rd party components
With the new .NET Core framework and libraries we have got an interface called Microsoft.Extensions.Logging.ILogger to be used for writing log messages. Various 3rd party and built-in components make very good use of it. To see how much is being logged just create a simple Web…
Pawel Gerr
entity framework core
Is "N+1 Queries" still a performance issue in Entity Framework Core 3?
In a previous post we saw that EF 2.1 is highly susceptible to the N+1 queries problem. After the release of a new version of Entity Framework Core (EF) the first question coming to mind is: "Is it still a big issue in EF 3.1?" And if the answer is no, is there anything else we…
Pawel Gerr