C# tutorials > Modern C# Features > C# 6.0 and Later > What are extended property patterns?

What are extended property patterns?

Extended property patterns in C# enhance pattern matching capabilities by allowing you to drill down into nested properties within an object and match against their values. This provides a more concise and readable way to express complex conditional logic.

Introduction to Extended Property Patterns

Extended property patterns were introduced to further enhance C#'s pattern matching capabilities. They allow you to examine the values of properties nested deep within an object hierarchy. This makes complex data validation and conditional branching much easier to read and maintain.

Instead of writing multiple nested if statements or using a chain of null-conditional operators and property accesses, you can use a single, expressive pattern to achieve the same result.

Basic Syntax

The syntax for extended property patterns involves using the property access operator (.) within the pattern. You can nest these property accesses to any depth. The example demonstrates how to check if a Person object has an Address and if that Address's City is "Anytown". The is operator is used for pattern matching.

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}

public class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

// Pattern matching with extended properties
Person person = new Person { Name = "John Doe", Address = new Address { Street = "123 Main St", City = "Anytown", ZipCode = "12345" } };

if (person is { Address: { City: "Anytown" } })
{
    Console.WriteLine("Person lives in Anytown");
}

Concepts Behind the Snippet

This code uses the is operator for pattern matching. The pattern { Address: { City: "Anytown" } } checks if the person object has an Address property that is not null, and if that Address object has a City property with a value of "Anytown". If both conditions are met, the if block is executed.

Real-Life Use Case

A common use case is validating complex data structures. Imagine processing data from an API where you need to ensure certain nested fields have specific values before performing further operations. Extended property patterns can simplify this validation process, making the code more readable and less prone to errors. This example show how to use extended property patterns to apply discounts based on the city the user lives in and the total purchase amount.

//Consider an e-commerce application where you need to apply discounts based on the user's location and purchase amount.

public class Customer
{
    public string Name { get; set; }
    public Address Address { get; set; }
    public decimal TotalPurchaseAmount { get; set; }
}

//Apply discount based on city and purchase amount
public decimal ApplyDiscount(Customer customer)
{
    decimal discount = 0;

    switch (customer)
    {
        case { Address: { City: "New York" }, TotalPurchaseAmount: > 100 }: //applying a discount when the customer is in new york and has a purchase of more than 100
            discount = 0.10m; // 10% discount
            break;
        case { Address: { City: "Los Angeles" }, TotalPurchaseAmount: > 50 }: //applying a discount when the customer is in Los angeles and has a purchase of more than 50
            discount = 0.05m; // 5% discount
            break;
        default:
            discount = 0;
            break;
    }

    return discount;
}

Best Practices

  • Keep patterns concise: Avoid overly complex patterns that are difficult to understand.
  • Handle nulls gracefully: Use null-conditional operators (?.) or nested patterns to handle potentially null properties.
  • Consider readability: Choose patterns that clearly express the intent of the code.

Interview Tip

When discussing extended property patterns in an interview, emphasize their role in improving code readability and maintainability. Explain how they reduce the need for verbose nested if statements and make complex conditional logic easier to understand. Be prepared to provide examples of real-world use cases where extended property patterns can be beneficial.

When to Use Them

Use extended property patterns when dealing with nested object hierarchies and you need to check the values of properties at multiple levels. They are particularly useful for data validation, conditional branching, and simplifying complex logical expressions.

Alternatives

Before extended property patterns, you would typically use a series of nested if statements or a combination of null-conditional operators and property accesses. While these approaches are functional, they can quickly become verbose and difficult to read, especially with deeper object hierarchies.

The example show how you would implement the same logic without extended property patterns, which is a less concise and harder to read alternative.

//The old way of implementing the same logic is with nested if statements. Consider the code below

Person person = new Person { Name = "John Doe", Address = new Address { Street = "123 Main St", City = "Anytown", ZipCode = "12345" } };

if (person != null && person.Address != null && person.Address.City == "Anytown")
{
    Console.WriteLine("Person lives in Anytown");
}

Pros

  • Improved Readability: Patterns are generally more concise and easier to understand than nested if statements.
  • Reduced Boilerplate: They eliminate the need for repetitive null checks and property accesses.
  • Enhanced Expressiveness: They provide a more declarative way to express complex conditional logic.

Cons

  • Potential Complexity: Overly complex patterns can be difficult to debug and maintain.
  • Learning Curve: Developers unfamiliar with pattern matching may require some time to learn the syntax and concepts.

FAQ

  • Can I use extended property patterns with custom types?

    Yes, extended property patterns work with any type that has accessible properties, including custom classes and structs.
  • How do I handle null values when using extended property patterns?

    Use the null-conditional operator (?.) or nested patterns to handle potentially null properties gracefully. For example: person is { Address: { Street: { Length: > 5 } } } would throw an exception if Address or Street is null. A safer approach would be: person is { Address: { Street: { Length: > 5 } } } or nest patterns.
  • Are there performance implications to using extended property patterns?

    In most cases, the performance impact of using extended property patterns is negligible. The compiler optimizes pattern matching expressions to be efficient. However, very complex patterns with deep nesting might have a slight performance overhead. Always measure performance if it is critical.