Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

C# Dictionary

  1. Home
  2. C# Dictionary
  3. is / as / Pattern Matching

is / as / Pattern Matching

Since: is / as C# 1.0(2002)
Pattern Matching C# 7.0(2017)

The is operator checks an object's type, as safely casts it, and pattern matching (switch expressions and when guards) was enhanced in C# 8 and later.

Syntax

bool result = obj is Type;

// Checks the type and assigns to a variable (pattern variable).
if (obj is Type variable) { ... }

// Safe cast (returns null on failure instead of throwing).
Type variable = obj as Type;

// Pattern matching with a switch expression.
string result = variable switch {
    Type1 v => ...,
    Type2 v when condition => ...,
    _ => defaultValue
};

Syntax List

SyntaxDescription
obj is TypeReturns bool indicating whether obj is the specified type. Returns false for null.
obj is Type vAssigns to variable v if the type matches (type pattern variable). Available from C# 7.
obj as TypeAttempts type conversion. Returns null on failure instead of throwing an exception. Cannot be used with value types.
switch expressionC# 8 and later. Each case is written with an arrow (=>) and the whole expression returns a value.
when guardAdds an additional condition to a switch case.

Sample Code

Program.cs
using System;

// Type check with is.
object value = "Hello";
if (value is string text)
{
    Console.WriteLine($"String: {text.ToUpper()}"); // HELLO
}

// Safe cast with as.
object number = 42;
string str = number as string; // Does not crash on failure.
Console.WriteLine(str == null ? "Conversion failed" : str); // Conversion failed

// Pattern matching with switch expression.
object[] testData = { 42, "abc", 3.14, true, null };
foreach (object item in testData)
{
    string description = item switch
    {
        int n when n > 100 => $"Large integer: {n}",
        int n => $"Integer: {n}",
        string s => $"String: {s}",
        double d => $"Double: {d}",
        bool b => $"Boolean: {b}",
        null => "null",
        _ => "Unknown type"
    };
    Console.WriteLine(description);
}

This produces the following output:

dotnet script is_as_pattern_match.csx
String: HELLO
Conversion failed
Integer: 42
String: abc
Double: 3.14
Boolean: True
null

Practical Pattern: Class Hierarchy Dispatch

A pattern for processing derived classes stored in a base-class collection by dispatching on type with pattern matching.

PatternDispatch.cs
using System;
using System.Collections.Generic;

// Base class for members.
abstract class Member
{
    public string Name { get; init; }
}

class Worker : Member
{
    public int Score { get; init; }
}

class Client : Member
{
    public bool HasFlag { get; init; }
}

class External : Member
{
    public int RemainingQuota { get; init; }
}

List<Member> members = new()
{
    new Worker { Name = "user_1", Score = 210 },
    new Client { Name = "user_2", HasFlag = true },
    new External { Name = "user_3", RemainingQuota = 99999 },
    new Worker { Name = "user_4", Score = 190 },
    new Client { Name = "user_5", HasFlag = true },
};

// Dispatches on type with pattern matching.
foreach (Member m in members)
{
    string info = m switch
    {
        Worker w when w.Score >= 200 => $"[Senior Worker] {w.Name} (Score: {w.Score})",
        Worker w => $"[Worker] {w.Name} (Score: {w.Score})",
        Client cl when cl.HasFlag => $"[Client/Flagged] {cl.Name}",
        Client cl => $"[Client] {cl.Name}",
        External ex => $"[External] {ex.Name} (Quota: {ex.RemainingQuota})",
        _ => $"[Unknown] {m.Name}"
    };
    Console.WriteLine(info);
}

This produces the following output:

dotnet script pattern_dispatch.csx
[Senior Worker] user_1 (Score: 210)
[Client/Flagged] user_2
[External] user_3 (Quota: 99999)
[Worker] user_4 (Score: 190)
[Client/Flagged] user_5

Practical Pattern: Property Pattern

Property patterns (C# 8 and later) allow matching based on an object's property values.

PropertyPattern.cs
using System;

record Record(string Owner, bool Active, int PageCount);

static string DescribeRecord(Record record) => record switch
{
    { Owner: "user_1", Active: true } => "Main record: in use (owner: user_1)",
    { Owner: "user_2", PageCount: > 0  } => $"Reference record: {record.PageCount} pages",
    { Active: false }                        => $"{record.Owner}'s record: completed",
    _ => $"{record.Owner}'s record"
};

var records = new[]
{
    new Record("user_1", true, 50),
    new Record("user_2", true, 200),
    new Record("user_3", false, 0),
    new Record("user_4", true, 30),
};

foreach (var record in records)
    Console.WriteLine(DescribeRecord(record));

This produces the following output:

dotnet script property_pattern.csx
Main record: in use (owner: user_1)
Reference record: 200 pages
user_3's record: completed
user_4's record

Common Mistakes

Common Mistake 1: No Null Check After as

When an as cast fails, it returns null. Accessing members of the result without a null check causes a NullReferenceException.

using System;

object obj = 42;

// NG: str will be null if conversion fails.
string str = obj as string;
Console.WriteLine(str.Length); // NullReferenceException is thrown.

This produces the following output:

dotnet run
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
using System;

object obj = 42;

// OK: The is pattern variable only enters the block when the cast succeeds.
if (obj is string str)
{
    Console.WriteLine(str.Length);
}
else
{
    Console.WriteLine("Not a string.");
}

This produces the following output:

dotnet run
Not a string.

Common Mistake 2: Using as with Value Types

as can only be used with reference types. Using it with value types such as int or struct causes a compile error.

using System;

object obj = 42;

// NG: int is a value type; as cannot be used (compile error).
// int n = obj as int; // error CS0077: The as operator must be used with a reference type

// OK: Use the is pattern.
if (obj is int n)
    Console.WriteLine($"int: {n}");

// OK: Use an explicit cast (throws InvalidCastException on failure).
int m = (int)obj;
Console.WriteLine($"int: {m}");

This produces the following output:

dotnet run
int: 42
int: 42

Overview

Since C# 7, is can check the type and assign the variable at the same time, eliminating the need to separately cast after an is check. You can write it in one line: if (obj is string s).

as works for reference type casts but cannot be used with value types (int, struct, etc.). Using it without checking for null afterward leads to a NullReferenceException. Always add a null check.

For providing default values when a value is null, see null coalescing operator ?? / ??=.

If you find any errors or copyright issues, please .