C# > Functional Programming > Pattern Matching > is Pattern

Using 'is' pattern matching for type checking and conversion

This snippet demonstrates how to use the is pattern in C# for type checking and performing conversions safely within a single expression. It illustrates a cleaner and more concise way to handle type-related logic compared to traditional casting and GetType() checks.

Basic 'is' Pattern Matching

The is pattern checks if an object is of a specific type and, if it is, assigns it to a new variable of that type. This allows you to perform the type check and the conversion in one step. If the object is not of the specified type, the is pattern returns false and the assignment does not occur. In the example, the 'shape is Circle circle' expression performs a type check and assigns the shape object to a circle variable only if the shape is actually a Circle. This is used within an if-else if block to handle different shape types.

public static string GetShapeDescription(object shape)
{
    if (shape is Circle circle)
    {
        return $"This is a circle with radius: {circle.Radius}";
    }
    else if (shape is Rectangle rectangle)
    {
        return $"This is a rectangle with width: {rectangle.Width}, height: {rectangle.Height}";
    }
    else if (shape is null)
    {
      return "Shape is null";
    }
    else
    {
        return "Unknown shape";
    }
}

public class Circle { public double Radius { get; set; } }
public class Rectangle { public double Width { get; set; } public double Height { get; set; } }

Concepts behind the snippet

The core concept is type checking and safe conversion using the is keyword with pattern matching. Traditional approaches often involve separate type checks and casting, which can be verbose and potentially unsafe if not handled carefully. The is pattern provides a more elegant and type-safe way to achieve the same result. The 'shape is null' condition is important, because if we don't handle null values, there will be an exception thrown.

Real-Life Use Case

Consider a scenario where you receive data from an external source, like a database or API, where the type of data returned can vary. Using is pattern matching, you can easily determine the type of data you received and process it accordingly without having to resort to a series of GetType() checks and explicit casts. Another example is handling UI events, where different event types might be triggered, and you need to handle them differently based on their specific properties. Pattern matching allows you to cleanly distinguish and process these events.

Best Practices

  • Prioritize is pattern matching over traditional type checking and casting when possible.
  • Ensure that you handle all possible types gracefully, including a default case or an 'unknown' type handler.
  • Keep your pattern matching logic concise and readable. Avoid overly complex or nested patterns.
  • Consider the order of your pattern matching conditions. Place more specific checks before more general checks.

Interview Tip

Be prepared to explain the benefits of is pattern matching over older approaches. Emphasize its improved readability, type safety, and conciseness. Also, be ready to discuss potential performance implications, although in most cases, the performance difference is negligible.

When to use them

Use is pattern matching when you need to check the type of an object and conditionally perform actions based on that type. This is especially useful when dealing with polymorphic types, inheritance hierarchies, or data from external sources with varying types.

Alternatives

Alternatives include using traditional GetType() and casting or employing the as operator for type conversion followed by a null check. However, these alternatives are generally less readable and more prone to errors than using is pattern matching.

Pros

  • Improved readability and conciseness
  • Enhanced type safety
  • Reduced boilerplate code
  • Direct variable assignment within the type check

Cons

  • Slight potential performance overhead compared to simple type checks (though often negligible)
  • Requires familiarity with pattern matching syntax

FAQ

  • What happens if the 'shape' is null?

    The 'shape is null' condition handles the null case, so there is no exception thrown when passing a null object.
  • Can I use 'is' pattern matching with interfaces?

    Yes, you can use 'is' pattern matching to check if an object implements a specific interface. For example: if (obj is IMyInterface myInterface) { ... }
  • Is there a performance difference between 'is' pattern matching and 'as' casting?

    While there might be a slight performance difference in some scenarios, it's usually negligible. The primary benefit of 'is' pattern matching is improved readability and type safety. If performance is critical, it's recommended to benchmark both approaches in your specific context.