Syntax
if (value is Type variable) { }\nvalue switch { pattern => result }Examples
Type Pattern with is
Testing and casting in a single step, avoiding a separate explicit cast afterward.
object item = "Hello";
if (item is string s)
{
Console.WriteLine($"It's a string of length {s.Length}");
}
object number = 42;
if (number is int n && n > 0)
{
Console.WriteLine($"Positive int: {n}");
}Property Patterns
Matching based on the properties of an object, useful for destructuring records and classes.
record Point(int X, int Y);
Point p = new Point(0, 5);
string description = p switch
{
{ X: 0, Y: 0 } => "Origin",
{ X: 0 } => "On the Y axis",
{ Y: 0 } => "On the X axis",
_ => "Somewhere else"
};
Console.WriteLine(description); // On the Y axisRelational and Logical Patterns
Matching numeric ranges and combining patterns with and/or/not.
string Classify(int age) => age switch
{
< 0 => "Invalid",
>= 0 and < 13 => "Child",
>= 13 and < 20 => "Teenager",
>= 20 => "Adult"
};
Console.WriteLine(Classify(15)); // Teenager
object value = 5;
if (value is not null and int)
{
Console.WriteLine("It's a non-null int");
}Pattern Matching in switch Statements
Pattern matching also works in traditional switch statements, not just switch expressions.
void Describe(object obj)
{
switch (obj)
{
case int n when n > 0:
Console.WriteLine($"Positive: {n}");
break;
case string s:
Console.WriteLine($"String: {s}");
break;
case null:
Console.WriteLine("Nothing here");
break;
default:
Console.WriteLine("Unknown type");
break;
}
}
Describe(42);
Describe("hi");Best practices
- Use "is Type variable" instead of a separate "is Type" check followed by an explicit cast - it combines both steps and avoids duplicating the type name
- Use property patterns to destructure and match on object shape directly in a switch expression, instead of a chain of separate if statements
- Combine relational patterns (< 0, >= 20) with switch expressions for clean, readable range-based branching
- Prefer pattern matching over manual "is" + cast + null checks scattered across multiple lines - it consolidates the logic and reduces the chance of a mismatched check
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>.Nullable Reference Types & Null-Coalescing
Since C# 8, nullable reference types let the compiler track and warn about potential null reference issues at compile time, even for reference types like string and custom classes (which were always implicitly nullable before). A type like string means 'never null' under this feature, while string? explicitly allows null. The null-coalescing operator (??) and null-conditional operator (?.) provide concise syntax for safely working with potentially-null values.