Two Question Marks in C#: Not a Mistake, But a Powerful Tool
\n\nImagine: you are writing code in C#, and suddenly you see the ?? construct. Your first thought — a typo? An extra character? In reality, this is one of the most elegant and useful operators in the language — the null-coalescing operator. If you have ever caught a NullReferenceException and cursed everything in sight — this operator will be your lifesaver.
In this article, we will break down what two question marks mean in C#, how to use them correctly, how they differ from the ternary operator, and show real-world examples from practice. Let's go!
\n\nWhat is the ?? Operator in C#?
\n\nThe ?? operator (two question marks) is a binary operator that returns the left operand if it is not null; otherwise, it returns the right operand. Simply put: "If the left side is not null — take the left side, otherwise take the right side."
The syntax is extremely simple:
\n\nvar result = left ?? right;\n\nWhere:
\n- \n
left— a value that can be null; \n right— a default value (cannot be null if the right side type is nullable). \n
First Example: Saving Yourself from null
\n\nSuppose you have a variable string? name (nullable string). You want to display the user's name, and if it's absent — "Guest":
string? name = GetUserName(); // may return null\nstring displayName = name ?? "Guest";\nConsole.WriteLine(displayName);\n\nWithout the ?? operator, you would have to write:
string displayName = (name != null) ? name : "Guest";\n\nAdmit it, the first option reads like a normal sentence: "name or guest". Elegant, right?
\n\nThe ??= Operator: The Next Generation of Null-Coalescing
\n\nStarting with C# 8.0, the ??= operator appeared — this is a shorthand assignment form with null-coalescing. It assigns the value of the right operand to the left operand only if the left operand is null.
Syntax:
\n\nleft ??= right;\n\nThis is equivalent to:
\n\nif (left == null) left = right;\n\nExample with ??=
\n\nList<int>? numbers = null;\nnumbers ??= new List<int>(); // numbers is now = new List<int>()\nnumbers.Add(42);\nConsole.WriteLine(numbers.Count); // 1\n\nNote: if numbers were already initialized (not null), the assignment would not occur. This is perfect for lazy initialization.
Comparison with the Ternary Operator (? :)
\n\nMany beginners confuse ?? with the ternary operator ? :. Let's settle this once and for all:
- \n
- Ternary operator — is a shorthand form of if-else. It checks ANY boolean condition:
condition ? value_if_true : value_if_false. \n - The ?? operator — checks ONLY for null. It is a specific case, tailored for one task. \n
Example of the ternary operator:
\n\nint age = 18;\nstring status = (age >= 18) ? "Adult" : "Minor";\n\nAnd here is what happens if you try to replace ?? with the ternary:
string? name = null;\nstring displayName = name != null ? name : "Guest"; // works, but longer\nstring displayName2 = name ?? "Guest"; // shorter and clearer\n\nConclusion: use ?? when you simply need to substitute a default value instead of null. For all other conditions — use the ternary operator.
Chaining the ?? Operator
\n\nYou can chain multiple ?? operators together. This is convenient when there are several possible sources for a value:
string? firstChoice = GetFromCache