The Ultimate Guide to Pattern Matching in C# 14

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, and not.
  • 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

  • and ensures all conditions must match.
  • or matches any condition.
  • not negates 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 switch expressions and is expressions.

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-else logic.
  • 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

DomainExample
Enterprise Validationif (order.Quantity is > 0 and <= 1000)
Financial SystemsriskScore switch { >=0 and <0.3 => "Low", >=0.3 and <0.7 => "Moderate" }
IoT Sensorsif (temperature is >= -40 and <= 85)
AI/ML Pipelinesif (dataPoint is >= 0 and <= 1)
Domain-Driven Designif (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

  1. Use switch expressions for mapping ranges or types to values.
  2. Combine relational and logical patterns for readability.
  3. Use property patterns for object validation.
  4. Integrate list and slice patterns for sequence handling.
  5. Keep patterns concise — avoid deep nesting for readability.
  6. 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.