言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

C#辞典

  1. トップページ
  2. C#辞典
  3. switch 文 / switch 式(C#)

switch 文 / switch 式(C#)

多岐分岐を簡潔に書くための『switch』文と、C# 8以降で導入された switch 式です。文字列・列挙型・型パターンなど様々な値に対してパターンマッチングができ、従来の if / else if の連鎖をすっきりまとめることができます。

構文

// 基本的なswitch文です。
switch (変数または式) {
	case 値1:
		// 値1と一致したときに実行されます。
		break;
	case 値2:
		// 値2と一致したときに実行されます。
		break;
	default:
		// どのcaseにも一致しないときに実行されます。
		break;
}

// 複数の値を同じcaseにまとめることができます。
switch (変数) {
	case 値1:
	case 値2:
		// 値1または値2のどちらかに一致したときに実行されます。
		break;
	default:
		break;
}

// goto caseでフォールスルーを明示的に行います。
switch (変数) {
	case 値1:
		// 処理後に値2のcaseへジャンプします。
		goto case 値2;
	case 値2:
		// 値1からgotoで来た場合も、値2に直接一致した場合も実行されます。
		break;
}

// C# 8以降: switch式です。変数を返す式として書けます。
var 結果 = 変数 switch {
	値1 => 返す値1,
	値2 => 返す値2,
	_ => デフォルト値
};

// whenガードで追加条件を付けることができます。
var 結果 = 変数 switch {
	型 v when 条件式 => 返す値,
	_ => デフォルト値
};

switch文とswitch式の比較

項目switch文switch式(C# 8以降)
書き方case / break / defaultアロー(=>)で値を返す
用途複数の処理を実行する場合値を選んで返すだけの場合
フォールスルーgoto caseで明示的に行うなし(各アームは独立)
default相当default:_ =>(ワイルドカード)
whenガードcase 値 when 条件:値 when 条件 =>
網羅性チェックなしコンパイラが警告を出す場合あり

サンプルコード

SwitchBasic.cs
using System;

class SwitchBasic {
	static void Main() {

		// --- 文字列に対するswitch文 ---
		// メンバー名で担当するスキルを判定します。
		string name = "member_3";

		switch (name) {
			case "member_2":
				Console.WriteLine(name + " は skill_a を担当しています。");
				break;
			case "member_3":
				Console.WriteLine(name + " は skill_b を担当しています。"); // こちらが実行されます。
				break;
			case "member_4":
				Console.WriteLine(name + " は skill_c を担当しています。");
				break;
			default:
				Console.WriteLine(name + " のスキルは不明です。");
				break;
		}

		// --- 複数のcaseをまとめる書き方 ---
		// グループAのメンバーかどうかを判定します。
		string member = "member_4";

		switch (member) {
			case "member_2":
			case "member_3":
			case "member_4":
				Console.WriteLine(member + " はグループAのメンバーです。"); // こちらが実行されます。
				break;
			case "member_5":
				Console.WriteLine(member + " はグループBのメンバーです。");
				break;
			default:
				Console.WriteLine(member + " のグループは不明です。");
				break;
		}

		// --- goto caseによるフォールスルー ---
		// 特定の条件から別のcaseへ処理を引き継ぎます。
		string level = "S";

		switch (level) {
			case "S":
				Console.WriteLine("レベルSとして認定されています。");
				goto case "A"; // Aのcaseへジャンプします。
			case "A":
				Console.WriteLine("上位タスクへの参加が許可されています。"); // S・Aともに実行されます。
				break;
			case "B":
				Console.WriteLine("標準タスクの処理が可能です。");
				break;
			default:
				Console.WriteLine("レベルが設定されていません。");
				break;
		}
	}
}

コンパイルして実行すると次のようになります。

dotnet script SwitchBasic.cs
member_3 は skill_b を担当しています。
member_4 はグループAのメンバーです。
レベルSとして認定されています。
上位タスクへの参加が許可されています。
SwitchEnum.cs
using System;

// スキルタイプを表す列挙型です。
enum SkillType {
	Analysis, // 分析
	Planning, // 計画
	Design, // 設計
	Review, // レビュー
	Unknown // 不明
}

class SwitchEnum {
	static void Main() {

		// --- 列挙型に対するswitch文 ---
		SkillType type = SkillType.Design;

		switch (type) {
			case SkillType.Analysis:
				Console.WriteLine("データの収集・解析を得意とします。");
				break;
			case SkillType.Planning:
				Console.WriteLine("プロジェクトの計画策定を担当します。");
				break;
			case SkillType.Design:
				Console.WriteLine("システムの設計を担当します。"); // こちらが実行されます。
				break;
			case SkillType.Review:
				Console.WriteLine("成果物のレビューを担当します。");
				break;
			default:
				Console.WriteLine("スキルが判明していません。");
				break;
		}

		// --- switch式で列挙型をもとに説明文を取得します ---
		SkillType[] types = {
			SkillType.Analysis,
			SkillType.Review,
			SkillType.Unknown
		};

		foreach (SkillType t in types) {
			string description = t switch {
				SkillType.Analysis => "基本的なデータ分析スキルです。",
				SkillType.Planning => "計画立案のスキルです。",
				SkillType.Design => "設計スキルの基盤です。",
				SkillType.Review => "レビューを担当するスキルです。",
				_ => "スキルが判明していません。"
			};
			Console.WriteLine(t + ": " + description);
		}
	}
}

コンパイルして実行すると次のようになります。

dotnet script SwitchEnum.cs
システムの設計を担当します。
Analysis: 基本的なデータ分析スキルです。
Review: レビューを担当するスキルです。
Unknown: スキルが判明していません。
SwitchExpression.cs
using System;

// ワーカーの基底クラスです。
class Worker {
	public string Name { get; set; }
	public Worker(string name) { Name = name; }
}

class SkilledWorker : Worker {
	public int Score { get; set; }
	public SkilledWorker(string name, int score) : base(name) {
		Score = score;
	}
}

// タスク担当クラスです。
class TaskItem : Worker {
	public string Level { get; set; }
	public TaskItem(string name, string level) : base(name) {
		Level = level;
	}
}

class SwitchExpression {
	static void Main() {

		// --- 型パターンとwhenガードを使ったswitch式 ---
		// ワーカー・タスク・その他を型で振り分けます。
		object[] entities = {
			new SkilledWorker("member_2", 1200),
			new SkilledWorker("member_1", 8500),
			new TaskItem("item_b", "S"),
			new TaskItem("item_d", "S"),
			"item_c (unclassified)"
		};

		foreach (object entity in entities) {
			string status = entity switch {
				SkilledWorker s when s.Score > 8000
					=> s.Name + " はレベルS候補です(スコア: " + s.Score + ")。",
				SkilledWorker s
					=> s.Name + " はワーカーです(スコア: " + s.Score + ")。",
				// レベルSのタスクの場合です。
				TaskItem c when c.Level == "S"
					=> c.Name + " はレベルSのタスクです。",
				// それ以外のタスクです。
				TaskItem c
					=> c.Name + " は " + c.Level + " タスクです。",
				// 文字列など上記以外の型です。
				string s
					=> s + "(不明なエンティティ)",
				// 上記いずれにも該当しない場合です。
				_ => "不明なエンティティです。"
			};
			Console.WriteLine(status);
		}

		// --- switch式でレベルに応じた手当額を計算します ---
		Console.WriteLine();
		string[] levels = { "S", "A", "B", "C", "D" };

		foreach (string level in levels) {
			int allowance = level switch {
				"S" => 500000,
				"A" => 200000,
				"B" => 100000,
				"C" => 50000,
				_ => 20000
			};
			Console.WriteLine("Level " + level + " の月額手当: " + allowance + " 円");
		}
	}
}

コンパイルして実行すると次のようになります。

dotnet script SwitchExpression.cs
member_2 はワーカーです(スコア: 1200)。
member_1 はレベルS候補です(スコア: 8500)。
item_b はレベルSのタスクです。
item_d はレベルSのタスクです。
item_c (unclassified)(不明なエンティティ)

Level S の月額手当: 500000 円
Level A の月額手当: 200000 円
Level B の月額手当: 100000 円
Level C の月額手当: 50000 円
Level D の月額手当: 20000 円

よくあるミス

break を書き忘れてコンパイルエラーになる

C# では case の末尾に break(または return / throw / goto case)がないとコンパイルエラーになります。C 言語や Java のように暗黙のフォールスルーはできません。

switch (value) {
	case 1:
		Console.WriteLine("one");
	case 2:
		Console.WriteLine("two");
		break;
}

switch 式で _ (ワイルドカード)を省略して警告が出る

switch 式ですべてのケースを網羅していない場合、コンパイラが警告を出します。列挙型以外を対象にする場合は _(ワイルドカード)を必ず書いて、想定外の値を処理してください。

string label = value switch {
	1 => "one",
	2 => "two",
	_ => "other" // ← これを省略しないでください。
};

概要

『C#』の switch 文は従来からある多岐分岐構文で、case で一致する値を指定し、処理の末尾に必ず break(または return / throw)を書く必要があります。C# では暗黙のフォールスルー(break を省略して次の case へ処理を流すこと)はコンパイルエラーになります。意図的に次の case へ処理を引き継ぎたい場合は goto case 値 を明示的に書いてください。

C# 8以降で導入された switch 式は、複数の選択肢から値を選んで返すだけのケースをコンパクトに書けます。各アームはアロー(=>)で区切られ、ワイルドカード(_)でデフォルト値を指定します。when キーワードでガード条件を追加すれば、型と値の組み合わせによる細かな分岐も1箇所にまとめることができます。コンパイラはすべてのケースが網羅されているかをチェックするため、書き漏れに早期に気づけます。

型によるパターンマッチングは『is / as / パターンマッチ』も合わせて参照してください。単純な真偽による分岐は『if / else』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。