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

 | Pawel Gerr

Article series Codesharing of the future Better experience through Roslyn Analyzers and Code Fixes ⬅ Testing Source Generators, Roslyn Analyzers and Code Fixes More background information about the smart-enums and the source code can be found on GitHub: Enum like classes (a.k.a…

Read article
 | Pawel Gerr

Article series Code sharing of the future ⬅ Better experience through Roslyn Analyzers and Code Fixes Testing Source Generators, Roslyn Analyzers and Code Fixes Code Sharing Today The most common approach for sharing code/functionality is providing base/helper classes or…

Read article
 | Pawel Gerr

Article series Code sharing of the future Better experience through Roslyn Analyzers and Code Fixes Testing Source Generators, Roslyn Analyzers and Code Fixes More information about the smart enums, the source code, and the documentation of can be found on GitHub: Enum-like…

Read article