Back to Blog
C#

C# var Pattern: Syntax, Use Cases, and Pitfalls

c# var pattern: Learn how the C# var pattern works, where it fits in pattern matching, and when it's useful versus other patterns.

C#pattern matchingvar patternswitch expressionstype patterns
C# var pattern illustration showing a variable assignment in a pattern matching context.

The C# var pattern is a pattern that matches any value and assigns it to a new variable. It is part of the pattern matching toolkit introduced in C# 7.0 and remains a useful tool in modern C# code. Unlike type patterns, the var pattern does not check the type of the input; it simply captures the value into a variable. This makes it a flexible choice in scenarios where you need to work with the matched value without restricting its type.

The Syntax of the var Pattern

The var pattern is written as var identifier. It can appear anywhere a pattern is expected, such as in an is expression, a switch statement, or a switch expression.

object input = "hello"; if (input is var value) { Console.WriteLine(value); // value is of type object }

In this example, value is assigned the value of input (which is "hello"). The type of value is object, because the var pattern does not perform any type conversion or narrowing. The pattern always succeeds, so the if block always executes.

In a switch statement, the var pattern can be used as a case that always matches. It is often placed last as a catch-all that also captures the value.

switch (input) { case int i: Console.WriteLine($"Integer: {i}"); break; case string s: Console.WriteLine($"String: {s}"); break; case var other: Console.WriteLine($"Other: {other}"); break; }

Here, other receives the input value if it is not an int or string. Because the var pattern matches everything, it acts like a default case that provides access to the value.

How var Pattern Differs from Type Patterns

A type pattern, such as int i or string s, only matches when the input is of that exact type (or a derived type for reference types). It also performs a cast and assigns the result to the variable. The var pattern, on the other hand, does not check the type at all. It assigns the input directly to the variable without any cast.

PatternMatchesVariable typeUse case
var xAny value, including nullSame as input typeCapture value without type restriction
int xOnly int or derivedintCheck and cast to a specific type
_ (discard)Any valueNoneIgnore the value

This distinction matters when you need to distinguish between null and non-null values. The var pattern matches null, while a type pattern like string s does not match null. If you want to capture a value but also ensure it is not null, you need a different approach, such as a property pattern or a type pattern with a null check.

Practical Use Cases for var Pattern

The var pattern shines in scenarios where you need to capture the input value inside a pattern-matching construct without altering its type. One common use is in switch expressions where you want to compute a result based on the value itself, not its type.

string Describe(object value) => value switch { int i => $"Integer {i}", string s => $"String of length {s.Length}", var other => $"Unknown type: {other?.GetType().Name}" };

In this switch expression, the var pattern captures the value into other so you can inspect its type or use it in the expression. Without the var pattern, you would have to rely on a discard _, which does not give you access to the value.

Another use case is in property patterns or recursive patterns where you need to bind a sub-expression to a variable. For example, you can use a var pattern inside a positional pattern to capture the entire input for later use.

if (point is (var x, var y)) { Console.WriteLine($"Coordinates: {x}, {y}"); }

Here, x and y are captured from the tuple, and the var pattern ensures they are assigned without type checks. This is particularly useful when working with tuples of unknown types.

Common Mistakes and Edge Cases

One common mistake is using the var pattern when you actually need a type check. Because var pattern matches everything, it can silently accept null or unexpected types. For instance, the following code will always enter the if block, even if input is null:

if (input is var value) { // This always runs, even if input is null }

If you intended to check for a specific type, use a type pattern instead. Another pitfall is placing a var pattern before other cases in a switch. Since it always matches, any subsequent cases become unreachable and the compiler will warn about them.

switch (input) { case var any: Console.WriteLine("This always matches"); break; case int i: // Compiler warning: unreachable break; }

To avoid this, place the var pattern last, after all specific type patterns. Also, note that the var pattern does not perform any null checks. If you need to exclude null, combine it with a property pattern or use a when clause.

Performance and Runtime Behavior

The var pattern has no runtime cost beyond a simple variable assignment. It does not involve type checks, boxing, or casting. The compiler treats it as a direct assignment of the input to the variable. This is in contrast to type patterns, which may involve a type check and an unboxing or cast operation, depending on the types involved.

Because the var pattern is resolved at compile time, it does not introduce any overhead in the generated IL. In performance-sensitive code, using a var pattern instead of a type pattern can avoid an unnecessary type check when you only need the value. However, the difference is usually negligible unless the pattern is in a hot loop.

One subtle behavior is that the variable declared with var pattern is read-only within the scope. You cannot assign a new value to it. This is consistent with other pattern variables and helps prevent accidental mutation.

When to Choose var Pattern Over Alternatives

The decision to use the var pattern comes down to whether you need the value and whether you need to restrict its type. Use the var pattern when:

  • You need to capture the input value in a pattern-matching construct.
  • You do not need to perform a type check or cast.
  • You want a catch-all case that also provides access to the value.

Use a type pattern when you need to verify the type and work with a strongly typed variable. Use a discard _ when you do not need the value at all. In many cases, a type pattern is more expressive and safer because it documents the expected type. The var pattern is best reserved for situations where the input type is genuinely unknown or where you need to pass the value through without modification.

A final consideration is code readability. Overusing the var pattern can obscure the intent of the code, especially if a type pattern would be more explicit. Use it judiciously, and always place it after more specific patterns in a switch to maintain clear control flow.

c# var pattern: Practical Usage and Code Examples | RYUSLOG DEV