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 = "Fola"; // 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
}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); // 0Null-Conditional Operator (?.)
Safely accessing a member only if the object isn't null, short-circuiting to null instead of throwing.
class Address { public string City = ""; }
class Person { public Address? Home; }
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 levelsNull-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("Fola");
Console.WriteLine(string.Join(", ", names));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
At a glance
- Purpose
- Applications on the .NET platform
- File extension
- .cs
- Runs in
- .NET runtime
- Usually used with
- .NET SDK and libraries
Specifications & further reading
Related C# documentation
A delegate is a type-safe reference to a method - essentially a variable that can hold a method and be invoked like one. Delegates enable passing behavior around as data, forming the foundation for events, callbacks, and LINQ. C# provides built-in generic delegate types, Func<> and Action<>, that cover the vast majority of use cases without needing to declare a custom delegate type.Events
An event is a special kind of delegate field that provides a publish-subscribe pattern: the declaring class can raise (invoke) the event, but external code can only subscribe (+=) or unsubscribe (-=) - it cannot invoke the event directly or overwrite existing subscribers. This makes events the standard, safe way to notify other parts of a program that something has happened, like a button being clicked or a value changing.Extension Methods
Extension methods let you add new methods to an existing type - including types you don't own, like built-in .NET types or third-party classes - without modifying its source code or creating a subclass. They're defined as static methods in a static class, with the first parameter prefixed with this to indicate which type they extend. LINQ's Where(), Select(), and friends are themselves implemented as extension methods on IEnumerable<T>.Pattern Matching
Pattern matching, expanded significantly since C# 7, lets you test a value against a shape or condition using is, switch expressions, and more, often extracting matched data in the same step. It covers type patterns (checking and casting in one step), property patterns (matching on an object's properties), and relational patterns (matching numeric ranges), making conditional logic more expressive and less error-prone than manual casting.