Pattern matching in C# 14 is one of the most transformative language features. It allows developers to write declarative, readable, and safe conditional logic, integrating type safety, runtime performance, and domain modeling. C# 14 introduces enhanced pattern matching with relational, logical, list, type, and property patterns, alongside negation and sequence matching. This guide provides a complete reference, including syntax, examples, best practices, performance considerations, and architectural implications.
1. Overview of Pattern Matching in C#
Pattern matching evaluates a value against a pattern and optionally extracts data if it matches. It reduces boilerplate compared to if-else statements, supports type safety, and integrates with modern C# features like switch expressions, tuples, and records.
C# 14 extends pattern matching to:
- Relational Patterns (
>,<,>=,<=) - Logical Patterns (
and,or,not) - List and Slice Patterns (
[first, second, ..rest]) - Type Patterns (
is Type variable) - Property Patterns (
{ Property: Pattern }) - Negation Patterns (
not)
2. Relational Patterns
Syntax
if (score is >= 90 and <= 100)
{
Console.WriteLine("Excellent!");
}
Features
- Express ranges directly within conditions.
- Combine with
and,or, andnot. - Fully optimised by the compiler and JIT.
Use Cases
- Grading systems, thresholds, financial scoring, sensor validation.
3. Logical Patterns
Logical patterns allow combining multiple patterns with operators:
if (value is < 0 or > 100)
{
Console.WriteLine("Out of range");
}
Features
andensures all conditions must match.ormatches any condition.notnegates a pattern.
Use Cases
- Complex validations, exception guards, multi-condition filters.
4. List & Slice Patterns
Syntax
int[] numbers = { 1, 2, 3, 4 };
if (numbers is [1, 2, .. var rest])
{
Console.WriteLine($"Remaining items: {string.Join(", ", rest)}");
}
Features
- Match arrays, spans, and sequences.
..captures the remaining elements.- Combine with relational and logical patterns.
Use Cases
- Parsing CSV/JSON, analysing sequences, preprocessing for AI/ML pipelines.
5. Type Patterns
Syntax
if (obj is string s)
{
Console.WriteLine($"String length: {s.Length}");
}
Features
- Checks type and optionally extracts a variable.
- Works with
switchexpressions andisexpressions.
Use Cases
- Safe casting, polymorphic behavior, dynamic input validation.
6. Property Patterns
Syntax
if (person is { Name: not null, Age: >= 18 })
{
Console.WriteLine("Valid adult");
}
Features
- Match object properties directly.
- Combine with relational, logical, and list patterns.
- Supports nested objects for deep matching.
Use Cases
- Domain models, API validation, DTO checks.
7. Negation Patterns
Syntax
if (temperature is not < 0 and not > 100)
{
Console.WriteLine("Safe range");
}
Features
- Explicitly exclude values or ranges.
- Can combine with other patterns.
Use Cases
- Guard clauses, safety checks, data sanitisation.
8. switch Expressions with Enhanced Patterns
Example
var category = score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
< 70 => "F",
_ => "Invalid"
};
Benefits
- Replaces nested
if-elselogic. - Compiler ensures exhaustiveness for enums, constants, and types.
- Supports ranges, types, property, and list patterns.
9. Combining Patterns
Patterns can be nested and combined for maximum expressiveness:
if (person is { Age: >= 18 and < 65, Address: { Country: "US" } })
{
Console.WriteLine("Eligible US adult");
}
- Combines property patterns, relational patterns, and nested object matching.
- Ideal for domain-specific validations and complex rules.
10. Real-World Applications
| Domain | Example |
|---|---|
| Enterprise Validation | if (order.Quantity is > 0 and <= 1000) |
| Financial Systems | riskScore switch { >=0 and <0.3 => "Low", >=0.3 and <0.7 => "Moderate" } |
| IoT Sensors | if (temperature is >= -40 and <= 85) |
| AI/ML Pipelines | if (dataPoint is >= 0 and <= 1) |
| Domain-Driven Design | if (customer is { Status: "Active", Age: >=18 }) |
11. Performance Considerations
- Compile-Time Optimisation: Patterns are compiled into efficient IL.
- JIT Enhancements: Branching and type checks are optimised for hot paths.
- Memory Efficiency: List and span patterns avoid heap allocations.
- Safe Runtime: Eliminates unnecessary casting and null checks.
12. Architectural Impact
- Maintainable Code: Declarative, readable, and concise conditions.
- Scalable Systems: Simplifies domain validation across large codebases.
- Functional Paradigm Support: Enhances functional-style, pattern-first coding.
- Cross-Platform Alignment: Works in cloud, desktop, mobile, and WebAssembly apps.
- AI/ML and Data Pipelines: Clean preprocessing and validation logic.
13. Best Practices
- Use
switchexpressions for mapping ranges or types to values. - Combine relational and logical patterns for readability.
- Use property patterns for object validation.
- Integrate list and slice patterns for sequence handling.
- Keep patterns concise — avoid deep nesting for readability.
- Use negation to handle exceptions or invalid states explicitly.
14. Summary
C# 14 enhances pattern matching across multiple dimensions:
- Relational patterns: Compare ranges declaratively.
- Logical patterns: Combine multiple checks safely.
- List patterns: Match arrays, spans, and slices efficiently.
- Type patterns: Extract values safely from objects.
- Property patterns: Validate nested properties cleanly.
- Negation: Explicitly exclude unwanted values.
Impact: Developers can now write safe, readable, maintainable, and high-performance code across enterprise applications, AI/ML pipelines, financial systems, IoT, and cloud services.
Enhanced pattern matching represents a fundamental shift in how C# handles conditional logic, making code more declarative, less error-prone, and fully aligned with modern software architecture principles.