The ?., ?? and ??= operators
As you already know, a variable of a class can hold null—a reference that leads nowhere. It is like a message where the space for the document link was left empty: there is nothing to open. Accessing a member through null stops the program with a NullReferenceException.
Here the message and the reference part ways. An empty space in a message is already the sender's mistake, while null in C# is a legitimate value: you can store it, compare it and pass it around. Only accessing a member through it stops the program.
That is why an object that may be missing is checked before use: if (boss != null). Such checks are needed all the time, and C# has three short operators for them.
In this lesson's examples, a type carries a question mark: Person?. It tells the compiler that the variable may end up holding null, and then the compiler does not warn about assigning null to it.
The ?. operator
The ?. operator accesses a member only if the left side is not null:
Person? boss = null;
string? name = boss?.Name;
Console.WriteLine(name == null); // True
boss = new Person();
boss.Name = "Anna";
Console.WriteLine(boss?.Name); // Anna
class Person
{
public string Name = "";
}Let's go through the example line by line:
Person? boss = null;—there is no boss yet.boss?.Nameseesnullinboss. Nobody touches the fieldName, and the whole expression givesnull. There is no exception.- The program prints
True:namegotnull. - Once
bossholds an object,boss?.Nameworks like a plainboss.Nameand printsAnna.
Read x?.Member like this: if x is null, the result is null; otherwise it is an ordinary member access. Methods are called through ?. too: with null in name, name?.ToUpper() returns null instead of throwing.
The ?? operator
The ?? operator supplies a value for the case of null. The expression a ?? b gives a if it is not null, and b otherwise. Together with ?., it replaces a whole check with if:
Person? guest = null;
Console.WriteLine(guest?.Name ?? "nobody"); // nobodyguest?.Name gives null, and ?? supplies "nobody". If guest held an object, its name would be printed.
Interviewers like to ask how to avoid a NullReferenceException. One answer is to check the reference before using it: with if, ?. or ??.
The ??= operator
The ??= operator assigns only if the variable holds null right now. If there is a value already, the variable does not change:
string? title = null;
title ??= "Untitled";
title ??= "Draft";
Console.WriteLine(title); // UntitledLet's go line by line:
titleholdsnull, so the first line with??=puts"Untitled"into it.- The second time,
titlealready holds a string, and"Draft"is not assigned. - The program prints
Untitled.
title ??= "Untitled" is a short form of title = title ?? "Untitled". This is how you give a default value to a variable that may still hold null.
Common mistake
A greeting was built from a string and ??, but without parentheses:
string? user = null;
Console.WriteLine("Hello, " + user ?? "guest"); // ✗The program compiles and prints Hello, with no name. ?? has a lower precedence than +, so C# first runs "Hello, " + user. Adding null to a string gives the string "Hello, ": in string concatenation, null turns into an empty string. The left side of ?? is not null, and "guest" is never used.
You need parentheses: "Hello, " + (user ?? "guest") prints Hello, guest.
Key points
x?.Membergivesnullifxisnull, and throws no exception.a ?? bgivesa, orbifaisnull;a ??= bwritesbintoaonly ifaholdsnull.?.and??often go together:guest?.Name ?? "nobody".??has a lower precedence than+, so you write"Hello, " + (user ?? "guest")with parentheses.