14.3. Nullable Types and Null Operators#
null is the source of countless runtime crashes. Modern C# (8+) provides tools to make null-handling explicit, safe, and concise.
14.3.1. Nullable Value Types#
By default, value types (int, double, bool) cannot be null. Append ? to opt in:
int x = null; // compile error
int? y = null; // OK
Check before use with .HasValue / .Value, or use the null operators below.
int? score = null;
if (score.HasValue)
Console.WriteLine($"Score: {score.Value}");
else
Console.WriteLine("No score yet.");
// Shorthand with null-coalescing
int display = score ?? 0;
Console.WriteLine($"Display: {display}"); // Display: 0
14.3.2. Nullable Reference Types (C# 8+)#
Enable with #nullable enable (or project-wide via <Nullable>enable</Nullable>).
Once enabled, string means non-nullable; string? means may be null.
The compiler warns if you dereference a potentially-null reference.
#nullable enable
string name = "Alice"; // cannot be null
string? nick = null; // may be null
// Console.WriteLine(nick.Length); // warning: dereference of possibly null
Console.WriteLine(nick?.Length); // OK — prints nothing if null
14.3.3. The Null Operators#
Operator |
Name |
Meaning |
|---|---|---|
|
Null-coalescing |
Return |
|
Null-coalescing assignment |
Assign |
|
Null-conditional |
Access |
|
Null-conditional index |
Index only if |
|
Null-forgiving |
Suppress the nullable warning (use sparingly) |
// ?? — null-coalescing
string? input = null;
string result = input ?? "(none)";
Console.WriteLine(result); // (none)
// ??= — assign only if null
input ??= "default";
Console.WriteLine(input); // default
// ?. — null-conditional chain
string[]? words = null;
int? len = words?.Length;
Console.WriteLine(len); // (nothing printed — len is null)
14.3.3.1. Chaining ?. and ??#
Combine them for safe, concise access with a fallback.
record Order(string? CustomerName, Address? ShippingAddress);
record Address(string City, string Zip);
Order? order = null;
// Safe deep access with fallback
string city = order?.ShippingAddress?.City ?? "Unknown";
Console.WriteLine(city); // Unknown
14.3.4. Pattern Matching and Null#
Pattern matching integrates cleanly with nullability:
string? s = GetValue();
string result = s switch
{
null => "(none)",
{ Length: 0 } => "(empty)",
_ => s
};
14.3.5. Practice#
Write
int SafeParse(string? input)that returns the parsed integer, or0ifinputis null or not a valid number. Useint.TryParse.Given
List<string?> names, use LINQ and??to produce aList<string>where every null is replaced with"Anonymous".Rewrite this safely using null operators:
if (user != null && user.Address != null) Console.WriteLine(user.Address.City);
Footnotes