C# has evolved tremendously — from a verbose OOP language into a sleek, expressive, and modern programming language.
With each version, Microsoft introduced powerful operators that make code safer, more concise, and easier to read.
Here’s your ultimate guide to all the important operators you should know in modern C#.
🔹 1. Null-Coalescing & Safe Navigation
These operators help you handle null values gracefully without throwing exceptions.
| Operator |
Example |
Description |
?? |
var name = input ?? "Unknown"; |
Returns the right-hand value if the left-hand is null. |
??= |
name ??= "Default"; |
Assigns a value only if the variable is null. |
?. |
var len = person?.Name?.Length; |
Safely navigates through objects that may be null. |
?[] |
var ch = text?[0]; |
Safely index into arrays or lists. |
! |
obj!.ToString() |
Null-forgiving operator — tells the compiler “I know this isn’t null.” |
is null / is not null |
if (value is null) |
Type-safe null comparison syntax. |
🔹 2. Pattern Matching (C# 8–12)
Pattern matching enables powerful, declarative logic without repetitive if/else chains.
| Pattern |
Example |
Description |
is |
if (x is int i) |
Checks type and assigns if match succeeds. |
is not |
if (obj is not string) |
Negated type match. |
switch expression |
var area = shape switch { Circle c => c.Radius, Rectangle r => r.Width, _ => 0 }; |
Expression-based switch replacement. |
| Property pattern |
if (person is { Age: > 18, Name: not null }) |
Matches properties directly. |
| Tuple pattern |
(x, y) switch { (0, 0) => "Origin", (_, 0) => "X-axis" } |
Match multiple values together. |
| Relational pattern |
if (n is > 0 and < 10) |
Match numeric or range conditions. |
| List pattern (C# 11+) |
if (nums is [1, 2, .. var rest]) |
Match array/list structure. |
| Slice pattern |
if (arr is [1, .. var middle, 10]) |
Match prefix and suffix with ... |
🔹 3. Expression & Lambda Enhancements
These operators make your code more concise and expressive.
| Operator |
Example |
Description |
=> |
public int Add(int x, int y) => x + y; |
Expression-bodied members. |
() => |
() => DoWork() |
Lambda expression syntax. |
_ |
_ = DoSomething(); |
Discard or wildcard variable. |
🔹 4. Assignment & Arithmetic Shortcuts
| Operator |
Example |
Description |
+=, -=, *=, /=, %= |
x += 5; |
Compound assignments. |
++ / -- |
count++; |
Increment or decrement. |
<<, >>, >>> |
uint n = a >>> 1; |
Bit shift operators; >>> is unsigned right shift (C# 11). |
🔹 5. Range & Index Operators (C# 8+)
| Operator |
Example |
Description |
^ |
var last = arr[^1]; |
Index from the end (1 = last element). |
.. |
var sub = arr[1..4]; |
Slice between start and end indexes. |
..^ |
arr[1..^1] |
Slice excluding first and last. |
🔹 6. Type and Reflection Helpers
| Operator |
Example |
Description |
as |
obj as string |
Safe type cast, returns null if fails. |
is |
if (obj is MyType) |
Checks runtime type. |
typeof |
typeof(string) |
Gets type info at compile time. |
nameof |
nameof(MyProperty) |
Gets identifier name as string. |
default |
default(int) |
Returns default value of a type. |
🔹 7. New Features in C# 12 / 13
| Feature |
Example |
Description |
| Primary constructors |
class Person(string Name, int Age) |
Compact way to declare constructor + properties. |
| Collection expressions |
var list = [1, 2, 3]; |
Simpler syntax for new List<int> { 1, 2, 3 }. |
| Inline arrays |
Span<int> span = [1, 2, 3]; |
Allocate arrays inline without new. |
| Default lambda parameters |
(int x = 0) => x * 2 |
Lambdas with default argument values. |
| Params collections (C# 13) |
void Log(params string[] msgs) |
Flexible params syntax with collections. |
💡 Quick Example
string? input = "";
string name = input ?? "Guest"; // null-coalescing
name ??= "Anonymous"; // assign if null
var len = name?.Length ?? 0; // null-safe access
if (name is { Length: > 5 }) { } // property pattern
var arr = [1, 2, 3, 4, 5];
var slice = arr[1..^1]; // [2,3,4]
var point = (x: 0, y: 0);
var message = point switch
{
(0, 0) => "Origin",
(_, 0) => "X-axis",
_ => "Other"
};
Modern C# syntax lets you write expressive, safe, and elegant code with minimal boilerplate.
If you’re upgrading from older C# versions, take time to learn the ??, ?.,
pattern matching, and range operators — they’ll make your code cleaner and far more readable.
Stay updated with C# 13 and .NET 9 releases, as the language continues evolving toward simplicity and power!