C#におけるswitch文は、プログラムの条件分岐を制御するための非常に強力な構文です。
かつてのC#では単純な値の一致確認が主な用途でしたが、近年のアップデートによってパターンマッチング機能が飛躍的に進化しました。
現在では、orを用いた複数条件の結合や、when句による詳細なガード条件の指定など、柔軟で読みやすい記述が可能になっています。
C#におけるswitch文の進化と複数条件の重要性
C#の歴史を振り返ると、switch文はバージョンを重ねるごとに洗練されてきました。
初期のC#では、caseラベルに定数しか指定できず、複数の条件に対して同じ処理を行うには「フォールスルー」と呼ばれる手法を用いるしかありませんでした。
しかし、C# 7.0以降の型パターン導入やC# 8.0のswitch式の登場、そしてC# 9.0での論理パターンの追加により、その表現力は劇的に向上しました。
現代のC#開発において、複雑なif-elseの連鎖を避け、switchを用いて宣言的に条件を記述することは、コードの可読性と保守性を高めるための必須テクニックと言えます。
特に複数の条件を1つのセクションでまとめたり、変数の値に基づいた動的なフィルタリングを行ったりする場面では、最新の構文を正しく理解しておくことが重要です。
複数条件を指定する基本:従来のフォールスルー
まずは、最も基本的な「複数の値に対して同じ処理を実行する」方法を確認しましょう。
C#のswitch文では、caseラベルを連続して記述することで、それらのいずれかに合致した場合に同じブロックを実行できます。
従来の記述方法の例
以下のコードは、入力された曜日によって「平日」か「休日」かを判定するシンプルな例です。
using System;
class Program
{
static void Main()
{
DayOfWeek day = DayOfWeek.Saturday;
// 複数のcaseラベルを並べて記述する
switch (day)
{
case DayOfWeek.Monday:
case DayOfWeek.Tuesday:
case DayOfWeek.Wednesday:
case DayOfWeek.Thursday:
case DayOfWeek.Friday:
Console.WriteLine("平日は仕事または学校です。");
break;
case DayOfWeek.Saturday:
case DayOfWeek.Sunday:
Console.WriteLine("休日はリフレッシュしましょう。");
break;
default:
Console.WriteLine("不明な曜日です。");
break;
}
}
}
休日はリフレッシュしましょう。
この記述方法は古くから存在しますが、条件が多くなると縦に長く伸びてしまうという欠点があります。
これを解決するのが、次節で解説するモダンなパターンマッチングです。
orパターンを用いたスマートな複数条件指定
C# 9.0以降では、論理パターン(Logical Patterns)が導入され、orキーワードを使用して1つのcase内に複数の条件を横並びで記述できるようになりました。
これにより、コードの行数を大幅に削減し、直感的な記述が可能になります。
orパターンの活用例
先ほどの曜日の判定を、orを用いて書き直すと以下のようになります。
using System;
class Program
{
static void Main()
{
string month = "August";
// orパターンを使用して複数の条件を1行で記述
switch (month)
{
case "July" or "August" or "September":
Console.WriteLine("夏休みのシーズンです。");
break;
case "December" or "January" or "February":
Console.WriteLine("冬の寒い時期です。");
break;
default:
Console.WriteLine("その他の季節です。");
break;
}
}
}
夏休みのシーズンです。
orパターンのメリットは、単なる値の列挙だけでなく、後述する関係パターンなどと組み合わせて複雑な条件を簡潔に表現できる点にあります。
また、andやnotと組み合わせることも可能で、条件分岐の自由度が非常に高くなっています。
switch式と論理パターンの組み合わせ
C# 8.0で導入されたswitch式は、値を返すための構文として非常に重宝されます。
これにC# 9.0の論理パターンを組み合わせることで、多分岐のロジックを驚くほど短く記述できます。
switch式での複数条件(or, and, 関係演算子)
数値の範囲や複数の値を判定する場合、以下のような記述が一般的です。
using System;
class Program
{
static void Main()
{
int score = 85;
// switch式と関係パターン、論理パターンの組み合わせ
string grade = score switch
{
>= 90 => "秀",
>= 80 and <= 89 => "優", // andを用いた範囲指定
70 or 71 or 72 => "良(ボーダーライン)", // 特定の値の列挙
>= 60 => "可",
_ => "不可" // デフォルトケース
};
Console.WriteLine($"成績評価は {grade} です。");
}
}
成績評価は 優 です。
この例では、>= や <= といった関係パターンと、and、or を組み合わせています。
従来のif文であれば冗長になりがちな範囲判定が、宣言的で美しいリスト形式にまとまっていることがわかります。
when句による詳細なガード条件の指定
特定のパターンに一致した上で、さらに複雑な動的条件(変数の比較やメソッドの戻り値など)をチェックしたい場合には、when句を使用します。
これを「ケースガード」と呼びます。
when句は、定数パターンや型パターンだけでは表現できない、実行時の状態に依存する条件を付加する際に非常に強力です。
when句を用いた実用的な例
using System;
class Program
{
static void Main()
{
object OrderDetails(int amount, bool isVip) => (amount, isVip) switch
{
// when句を使用して、特定の条件を満たす場合のみマッチさせる
int n when n >= 10000 && isVip => "VIP顧客の高額注文(20%割引適用)",
int n when n >= 10000 => "一般顧客の高額注文(10%割引適用)",
int n when n < 0 => throw new ArgumentException("金額が不正です"),
_ => "通常注文"
};
Console.WriteLine(OrderDetails(15000, true));
Console.WriteLine(OrderDetails(15000, false));
}
}
VIP顧客の高額注文(20%割引適用)
一般顧客の高額注文(10%割引適用)
上記のように、whenの後ろには任意のブール式を記述できます。
パターンマッチング自体は値の「形」を見ているのに対し、whenはその「中身」や「外部状況」を判定するために使われます。
タプルパターンを用いた複数変数の同時判定
複数の変数を組み合わせて条件分岐を行いたい場合、タプルパターンが最適です。
これは、複数の値を一時的なタプルにまとめ、その組み合わせに対してパターンマッチングを行う手法です。
タプルによる複数条件の整理
例えば、ユーザーの権限とログイン状態を同時にチェックする場合、以下のように書けます。
using System;
class Program
{
static void Main()
{
string role = "Admin";
bool isAuthenticated = true;
// タプル (role, isAuthenticated) に対してマッチングを行う
string message = (role, isAuthenticated) switch
{
("Admin", true) => "管理者パネルにアクセス可能です。",
("User", true) => "マイページを表示します。",
(_, false) => "ログインが必要です。", // _ はワイルドカード
_ => "アクセス権限がありません。"
};
Console.WriteLine(message);
}
}
管理者パネルにアクセス可能です。
タプルパターンを使用することで、if文をネスト(入れ子)にすることなく、条件の組み合わせをマトリックスのように整理して記述できます。
これは、複雑なビジネスロジックを整理する際に非常に有効なテクニックです。
リストパターンによる配列・リストの複数条件判定
C# 11から導入されたリストパターンを使用すると、配列やリストの要素数や特定の要素の並びに対してswitch文を適用できます。
これも複数条件の一種として非常に強力です。
リストパターンの活用
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
string result = numbers switch
{
[] => "空のリストです。",
[1, 2, _] => "1と2で始まり、要素が3つのリストです。",
[.., 10] => "最後が10で終わるリストです。",
{ Length: > 5 } => "5要素より多いリストです。",
_ => "その他のリストです。"
};
Console.WriteLine(result);
}
}
1と2で始まり、要素が3つのリストです。
[1, 2, _] のような記述は、「最初の要素が1」「2番目が2」「要素数が合計3」という3つの条件を同時に満たすことを意味しています。
このように、データの構造そのものを条件として扱えるのが現代的なC#の強みです。
パフォーマンスとベストプラクティス
多くの条件をswitch文で扱う際、パフォーマンスが気になるかもしれませんが、一般的にC#のswitchは非常に効率的にコンパイルされます。
| 項目 | 特徴 |
|---|---|
| ジャンプテーブル | 連続した整数の値などを判定する場合、コンパイラはジャンプテーブルを作成し、O(1)に近い速度で分岐します。 |
| ハッシュ判定 | 文字列の判定では、ハッシュ値を用いて効率的に分岐が行われます。 |
| 評価順序 | switch文や式は、上から順に評価されます。そのため、より具体的、あるいは頻度の高い条件を上に書くのがセオリーです。 |
記述の際の注意点
- 重複するパターン: より広い範囲をカバーする条件を先に書いてしまうと、その下の詳細な条件に到達しなくなります。
- 網羅性の確保:
switch式を使用する場合、すべてのパターンを網羅するか、必ずデフォルトケース(_)を含める必要があります。そうしないと、実行時に例外がスローされる可能性があります。 - 可読性の維持: 複雑すぎる
when句は、メソッドとして切り出すなどして、switch文自体の見通しを良く保ちましょう。
まとめ
C#のswitch文は、単なる等価比較の道具から、高度なパターンマッチングエンジンへと進化を遂げました。
- orパターン を使えば、複数の候補値を1行で簡潔にまとめられます。
- 関係パターン(<, >= 等) と andパターン を組み合わせれば、数値範囲の判定が容易になります。
- when句 を活用することで、動的な条件や複雑なロジックを分岐に組み込めます。
- タプルパターン は、複数の変数の組み合わせを整理するのに最適です。
これらの機能を適切に使い分けることで、バグが少なく、意図が明確に伝わるコードを記述できるようになります。
最新のC#の機能を積極的に取り入れ、よりスマートな条件分岐を実装していきましょう。
