Codectionary / Developer documentation / C#

Nullable Reference Types & Null-Coalescing

Since C# 8, nullable reference types let the compiler track and warn about potential null reference issues at compile time, even for reference types like string and custom classes (which were always implicitly nullable before). A type like string means 'never null' under this feature, while string? explicitly allows null. The null-coalescing operator (??) and null-conditional operator (?.) provide concise syntax for safely working with potentially-null values.

Read the syntax

With nullable analysis enabled, string is intended to be non-null and string? may be null; the compiler reports warnings, not runtime validation guarantees.

?? chooses a fallback, ?. stops member access on null, and ??= assigns only when the left side is null. Check uncertain values before dereferencing them.

Syntax

string? maybeNull = null;\nvar result = value ?? defaultValue;

Examples

Nullable vs Non-Nullable Reference Types

With nullable reference types enabled, the compiler warns if a non-nullable reference might be null.

#nullable enable

string name = "John";       // never null (compiler-enforced, with warnings on violation)
string? nickname = null;     // explicitly allowed to be null

Console.WriteLine(name.Length);       // safe, no warning
// Console.WriteLine(nickname.Length);  // compiler WARNING - could be null
if (nickname != null)
{
    Console.WriteLine(nickname.Length);  // safe now, compiler knows it's checked
}
  1. With nullable reference types enabled, the compiler warns if a non-nullable reference might be null.
  2. With nullable analysis enabled, string is intended to be non-null and string? may be null; the compiler reports warnings, not runtime validation guarantees.
  3. name.Length prints 4. nickname is null, so the guarded block does not run; uncommenting the unguarded dereference triggers a nullable warning.

Null-Coalescing Operator (??)

Providing a fallback value when something might be null, in a single concise expression.

string? input = null;
string result = input ?? "default value";
Console.WriteLine(result);  // default value

int? maybeAge = null;
int age = maybeAge ?? 0;
Console.WriteLine(age);  // 0
  1. Providing a fallback value when something might be null, in a single concise expression.
  2. With nullable analysis enabled, string is intended to be non-null and string? may be null; the compiler reports warnings, not runtime validation guarantees.
  3. Both left operands are null, so ?? selects default value and 0. The two lines print those fallback values.

Null-Conditional Operator (?.)

Safely accessing a member only if the object isn't null, short-circuiting to null instead of throwing.

Person p = new Person();  // p.Home is null

string? city = p.Home?.City;  // null, instead of a NullReferenceException
Console.WriteLine(city ?? "No address on file");

int? length = p.Home?.City?.Length;  // chains safely through multiple levels

class Address { public string City = ""; }
class Person { public Address? Home; }
  1. Safely accessing a member only if the object isn't null, short-circuiting to null instead of throwing.
  2. With nullable analysis enabled, string is intended to be non-null and string? may be null; the compiler reports warnings, not runtime validation guarantees.
  3. Home is null; ?. yields null instead of dereferencing it. The fallback prints No address on file, and length remains nullable.

Null-Coalescing Assignment (??=)

Assigning a value only if the variable is currently null.

List<string>? names = null;

names ??= new List<string>();  // only assigns if names is currently null
names.Add("John");

Console.WriteLine(string.Join(", ", names));
  1. Assigning a value only if the variable is currently null.
  2. With nullable analysis enabled, string is intended to be non-null and string? may be null; the compiler reports warnings, not runtime validation guarantees.
  3. Because names starts null, ??= creates a list once. Add stores John, and Join prints John.

Best practices

  • Enable nullable reference types (<Nullable>enable</Nullable> in the project file) for new projects - it catches a huge class of NullReferenceException bugs at compile time
  • Use ?. and ?? together (obj?.Property ?? defaultValue) for concise, safe access with a fallback in a single expression
  • Use ??= to lazily initialize a variable only if it is currently null, instead of a longer explicit if check
  • Treat compiler nullable warnings seriously rather than suppressing them with ! (the null-forgiving operator) unless you are certain a value cannot actually be null at that point

Runtime & versions

.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

C# language reference

Specifications & further reading