C# には型の安全なチェックとキャストのために is と as という 2 つのキーワードがあります。C# 7.0 以降はパターンマッチングと組み合わせることで、より簡潔に型判定とキャストを同時に行えるようになりました。
本記事では基本的な使い方から、if 文・switch 文・switch 式でのパターンマッチングまでバリエーションを整理します。
キャスト方法の比較
C# での型変換には大きく 3 つの方法があります。
| 方法 | 変換失敗時 | 用途 |
|---|---|---|
(Type)obj (直接キャスト) |
InvalidCastException |
確実に変換できると分かっている場合 |
obj as Type |
null を返す |
失敗しても例外を出したくない場合(参照型のみ) |
obj is Type |
false を返す |
型チェックのみ行う場合 |
as — 安全なキャスト
as 演算子は型変換を試み、失敗した場合は例外を投げず null を返します。参照型と null 許容値型にのみ使用できます(int などの値型には使えません)。
object obj = "Hello, C#";
string? text = obj as string;
if (text != null)
{
Console.WriteLine(text.ToUpper()); // HELLO, C#
}
変換できない型を渡すと null になります。
object obj = 42;
string? text = obj as string;
Console.WriteLine(text); // (何も出力されない。text は null)
as の注意点は、変換に失敗した理由(型が違う/null だった)が区別できないことです。それを区別したい場合は is を使います。
is — 型チェック
is 演算子はオブジェクトが指定した型であるかを bool で返します。
object obj = "Hello";
if (obj is string)
{
Console.WriteLine("string 型です");
}
ただし、この書き方では型確認後に別途キャストが必要です。C# 7.0 以降はパターンマッチングでチェックとキャストを同時に行えます。
is によるパターンマッチング(C# 7.0+)
is 型名 変数名 と書くと、型チェックが true の場合に自動的にキャストされた変数が宣言されます。
object obj = "Hello, C#";
if (obj is string text)
{
// このブロック内で text は string 型として使える
Console.WriteLine(text.ToUpper()); // HELLO, C#
}
as + null チェックと等価ですが、より意図が明確になります。
// 従来の書き方(as + null チェック)
string? text1 = obj as string;
if (text1 != null) { ... }
// パターンマッチングを使った書き方
if (obj is string text2) { ... }
変数のスコープは if ブロックの外まで広がりますが、型チェックが false の場合は未代入扱いになります。
if (obj is string result)
{
Console.WriteLine(result); // ここで使える
}
// result はここでも構文上は参照できるが、型チェックが false だった場合は未代入
switch 文でのパターンマッチング(C# 7.0+)
switch 文の case にもパターンマッチングが使えます。
object shape = new Circle { Radius = 5.0 };
switch (shape)
{
case Circle c:
Console.WriteLine($"円: 半径 {c.Radius}");
break;
case Rectangle r:
Console.WriteLine($"長方形: {r.Width} x {r.Height}");
break;
case null:
Console.WriteLine("null です");
break;
default:
Console.WriteLine("不明な図形");
break;
}
when 句で追加条件を指定することもできます。
switch (shape)
{
case Circle c when c.Radius > 10:
Console.WriteLine("大きな円");
break;
case Circle c:
Console.WriteLine("小さな円");
break;
default:
break;
}
switch 式でのパターンマッチング(C# 8.0+)
switch 式はより簡潔に書けます。戻り値を返す場合に特に有効です。
object shape = new Circle { Radius = 5.0 };
string description = shape switch
{
Circle c when c.Radius > 10 => $"大きな円(半径 {c.Radius})",
Circle c => $"小さな円(半径 {c.Radius})",
Rectangle r => $"長方形({r.Width} x {r.Height})",
null => "null",
_ => "不明な図形",
};
Console.WriteLine(description);
プロパティパターン(C# 8.0+)
型だけでなく、プロパティの値も同時に条件指定できます。
object obj = new Person { Name = "Alice", Age = 30 };
if (obj is Person { Age: >= 18 } adult)
{
Console.WriteLine($"{adult.Name} は成人です");
}
switch 式でも同様に使えます。
string category = person switch
{
{ Age: < 13 } => "子ども",
{ Age: < 18 } => "ティーンエイジャー",
{ Age: < 65 } => "成人",
_ => "高齢者",
};
タプルパターン(C# 8.0+)
複数の値をまとめてパターンマッチングできます。
(string role, bool isActive) user = ("admin", true);
string message = user switch
{
("admin", true) => "管理者(有効)",
("admin", false) => "管理者(無効)",
(_, true) => "一般ユーザー(有効)",
_ => "一般ユーザー(無効)",
};
null チェックパターン(C# 9.0+)
is null / is not null で null チェックが書けます。== による比較と異なり、== 演算子のオーバーロードを無視して正確に null を判定します。
string? name = GetName();
if (name is null)
{
Console.WriteLine("name は null です");
}
if (name is not null)
{
Console.WriteLine(name.ToUpper());
}
論理パターン(C# 9.0+)
and / or / not を使って複合条件を書けます。
object obj = 42;
// or パターン
if (obj is int or long)
{
Console.WriteLine("整数型です");
}
// and パターン(範囲チェック)
if (obj is int n and >= 0 and <= 100)
{
Console.WriteLine($"{n} は 0〜100 の範囲です");
}
// not パターン
if (obj is not string)
{
Console.WriteLine("string 型ではありません");
}
まとめ
| パターン | 構文例 | C# バージョン |
|---|---|---|
| 型チェックのみ | obj is string |
1.0 |
| 安全なキャスト | obj as string |
1.0 |
| 型チェック+変数宣言 | obj is string s |
7.0 |
| switch 文の型パターン | case Circle c: |
7.0 |
| when 句 | case Circle c when c.Radius > 10: |
7.0 |
| switch 式 | shape switch { Circle c => ... } |
8.0 |
| プロパティパターン | obj is Person { Age: >= 18 } |
8.0 |
| タプルパターン | (x, y) switch { (0, 0) => ... } |
8.0 |
| null チェック | obj is null / obj is not null |
9.0 |
| 論理パターン | obj is int or long |
9.0 |
パターンマッチングは C# バージョンが上がるにつれて表現力が増しています。基本の as / is から始め、必要に応じてパターンマッチングの構文を取り入れると、型判定のコードをより安全かつ簡潔に書けます。