WisdomSoft - for your serial experiences.

switch文

特定の値を対象に、プログラムを多分岐させる switch 文について解説します。エラー数値の解析やメッセージ処理などに役に立ちます。

多分岐

if 文を用いればあらゆる条件分岐を表現できますが、単一の値から多くの分岐がある場合 if 文では if-else の階層が多くなってしまいます。ある特定の式の結果から複数の処理に分岐させたい場合は、if 文よりも switch 文(switch statement)が有効です。

switch 文
switch ()
{
case 定数式1:
	...
	ジャンプ文
case 定数式2:
	...
	ジャンプ文
...
}

冒頭の switch キーワードの直後に来る丸括弧内の式に分岐に利用する式を指定します。if 文と違い switch 文に指定する指揮は bool 型ではなく、整数型、char、string、enum型のいずれかでなければいけません。enum は列挙型と呼ばれるもので、これについては後記します。

switch 文の本体は中確固 { } で囲みます。これはブロック文ではなく switch ブロック(switch block)と呼ばれる switch 文の一部です。

switch ブロック内は冒頭の式の結果に対応する case キーワードと定数式を記述します。これを switch ラベル(switch label)と呼びます。switch 文は、式の評価結果に対応する switch ラベルに制御を移動させ、以降の文を実行します。if 文の埋め込み文とは異なり switch ラベルには任意の文を、任意の数だけ指定できます。

switch ラベルの最後は switch 文から抜け出すためのジャンプ文が指定されていなければなりません。ジャンプ文にはいくつかの種類が存在しますが、通常 switch 文を抜け出すためのコードには break 文(break statement)が用いられます。

break 文
break;

break 文は特にパラメータを持たず、break キーワードと終端を表すセミコロン ; だけで構成されます。break 文には、現在実行しているブロックを抜け出すという効果があり、switch 文の中で利用した場合、実行中の switch 文を抜け出します。

switch ラベルと、ラベルに関連付けられるジャンプ文までの一連の文を合わせて switch セクション(switch section)と呼びます。

図1 switch文の流れ
switch文の流れ

C/C++ 言語など他のプログラミング言語では break が存在しなければ、継続して次の switch セクションが実行されるという仕様でした。この現象をフォールスルーと呼びますが C# ではフォールスルーの禁止(no fall through)規則により switch ラベルの末尾に指定するジャンプ文が必須となっています。

switch (i)
{
case 0:
	System.Console.WriteLine("Case 0");
	break;
case 1:
	System.Console.WriteLine("Case 1");
	break;
case 2:
	System.Console.WriteLine("Case 2");
	break;
}

上のコードは標準的な switch 文の利用例です。式に指定している i 変数は整数型に互換性があるものとし、この値が 0 であれば case 0 ラベル以降の文が実行され、1 であれば case 1 ラベル以降の文が実行される仕組みです。

case ラベルは任意の数だけ記述できますが、同じ値の case ラベルを重複して指定することはできません。値の順序に制約はありませんが、整数の switch 文では昇順に並べると読みやすいでしょう。

コード1
class Test
{
	static void Main()
	{
		int message = 1;
		switch (message)
		{
		case 0:
			System.Console.WriteLine("WINNING THE WAR ON PANTS!");
			break;
		case 1:
			System.Console.WriteLine("Make a CONTRACT with Me!");
			break;
		case 2:
			System.Console.WriteLine("I have no interest in ordinary humans.");
			break;
		}
	}
}
実行結果
コード1 実行結果

コード1において message 変数は事前に定められたメッセージに対応する整数値を受ける変数だと想定します。メッセージに対応する値が多様に定義されているならば、if で個別に検索するよりも、このように switch 文で分岐させたほうが効率的でしょう。message 変数の値を変更して、適切な case ラベルの文が実行されることを確認してください。

defaultラベル

switch 文で式を評価した結果、どの case ラベルにも該当しない場合に実行したい文がある場合は default ラベル(default label)を使用します。default ラベルは case ラベルと同様に switch ラベルの一種として扱われます。 

defaultラベルを持つswitch 文
switch ()
{
case 定数式1:
	...
	ジャンプ文
case 定数式2:
	...
	ジャンプ文
default:
	...
	ジャンプ文
}

式に指定した値がどの case ラベルの値にも該当しなかった場合、default ラベルの文が処理されます。

図2 switch文の流れ
defaultラベルを持つswitch文の流れ

case ラベルは定数式の値が重複しない限り任意の数だけ指定できますが dufault ラベルは 1 つしか指定できません。

switch (i)
{
case 0:
	System.Console.WriteLine("Case 0");
	break;
case 1:
	System.Console.WriteLine("Case 1");
	break;
default:
	System.Console.WriteLine("Default");
	break;
}

case ラベルと default ラベルの出現順序は自由です。慣例的に default ラベルは最後の switch セクションとして配置されますが、case ラベルの switch セクションにまたがる形で記述しても構文上の問題はありません。

switch (i)
{
case 0:
	System.Console.WriteLine("Case 0");
	break;
default:	//OK
	System.Console.WriteLine("Default");
	break;
case 1:
	System.Console.WriteLine("Case 1");
	break;
}

switch 文の中に指定する switch ラベルの数は任意です。そのため、意味はありませんが default ラベルしか持たない switch 文や、switch ブロックに何も書かれていない空の switch 文なども構文上は有効です。

コード2
class Test
{
	static void Main()
	{
		int message = 10;
		switch (message)
		{
		case 0:
			System.Console.WriteLine("夢の中で逢った、ような……");
			break;
		case 1:
			System.Console.WriteLine("それはとっても嬉しいなって");
			break;
		default:
			System.Console.WriteLine("わけがわからないよ");
			break;
		}
	}
}
実行結果
コード2 実行結果

コード2は default ラベルを持つ switch 文を用意し、意図的に case ラベルとは一致しない適当な値を switch 文の条件に指定しています。実行結果を見れば case ラベルに一致しない値の場合は default ラベルに制御が移ることが確認できます。 

文字列による分岐

C# の switch 文は文字列型を指定して分岐させることができます。式に指定した文字列が case ラベルに指定した文字列と一致すれば、対象の case ラベルに制御が移ります。文字列の一致条件は等価演算子と同じで、文字列の長さと文字の並びが完全に等しい時、同じ文字列だと判断されます。

コード3
class Test
{
	static void Main()
	{
		string name = "Mami";
		switch (name)
		{
		case "Madoka":
			System.Console.WriteLine("こんなの絶対おかしいよ");
			break;
		case "Homura":
			System.Console.WriteLine("その必要はないわ");
			break;
		case "Sayaka":
			System.Console.WriteLine("あたしって、ほんとバカ");
			break;
		case "Kyoko":
			System.Console.WriteLine("どういうことだ、おい…");
			break;
		case "Mami":
			System.Console.WriteLine("逝ってしまったわ、円環の理に導かれて…");
			break;
		}
	}
}
実行結果
コード3 実行結果

大文字と小文字も区別するという点で注意してください。