switch文

switch文

if文を用いればどんな条件判定でも可能です。
しかし場合によってはswitch文を用いたほうが記述が簡単になる場合があります。


static void Main(string[] args)
{
    string str = "ab";

    switch (str.Length)
    {
        case 3:
            Console.WriteLine("strのサイズは3");
            break;
        case 2:
            Console.WriteLine("strのサイズは2");
            break;
        case 1:
            Console.WriteLine("strのサイズは1");
            break;
        case 0:
            Console.WriteLine("strのサイズは0");
            break;
        default:
            Console.WriteLine("strは予期しないサイズ");
            break;
    }

    Console.ReadLine();
}
strのサイズは2

switch文はある変数の値によって処理を複数に振り分けたい場合に便利です。
switch文は、一致式(switchキーワード直後に指定する式)の値と一致するcase句の文が実行されます。
(変数ならその値、式ならその演算結果、メソッドなら戻り値)

case句の値には変数は指定できず、定数(リテラルも含む)を指定する必要があります。
定数とは、変数のようにプログラムの実行状況によって変化することのない値です。
コード中に直接記述される文字列や数値などは定数です。
(詳しくはリテラル定数列挙型を参照)

case句の行末で使用するのはセミコロン(;)ではなくコロン(:)であることに注意してください。

ひとつのcase句の終わりにはbreak文を記述します。
break文はswich文の処理を終了させます。
break文を書かないとエラーになります。

default句

switch文は与えられた値に一致するcase句の処理を実行しますが、どのcase句にも一致しなかった場合にはdefault句が実行されます。
default句には何も定数値を指定せず、コロンだけを記述します。
必要がない場合はdefault句は省略できます。

複数のcase句をまとめる

いくつかのcase句で同じ処理を実行したい場合はcase句をまとめることができます。


string str = "abc";

switch (str)
{
    case null:
    case "":
        Console.WriteLine("strはnullまたは空文字");
        break;
    default:
        Console.WriteLine(str);
        break;
}

このコードは変数strがnullまたは空の場合に同じcase句を実行します。

ただし、case句に何か文がある場合はそのまま下のcase句に流れ落ちることはできません。


string str = "abc";

//このswitch文はエラー
switch (str)
{
    case "":
        Console.WriteLine("strは空文字");
    default:
        Console.WriteLine(str);
        break;
}

上のswitch文はcase "":句の最後にbreak文がないためエラーになります。
C言語などではこの文法(フォールスルーという)は許可されていますが、C#では許可されていません。

switch式

上で説明したswitchは、文法上は「文」というものに分類されます。

文は大まかに言えば評価ができない処理です。
例えばswitchを実行した結果の値を得ることはできません。
void型を返すとかではなく、文は評価自体が不可能です。

switch式は、文ではなく「式」形式のswitchです。
式は大まかに言えば評価することができる処理です。
(評価値がvoidである場合もあります)

つまりswitch式は、switch文のように条件分岐を行い、その結果の値を受け取ることができます。
switch式はC#8.0以降で使用できます。


int num = 1;

string s = num switch
{
    0 => "日",
    1 => "月",
    2 => "火",
    3 => "水",
    4 => "木",
    5 => "金",
    6 => "土",
    _ => ""
};

Console.WriteLine(s);

このint型変数numの中身は1なので、それに対応する式の評価値(今回はstring型)が変数sに格納されます。
最後のアンダーバー(_)については後述します。

switch式はswitch文とはやや書式が異なります。


一致式 switch
{
    パターン1 => 式1,
    パターン2 => 式2,
    ...
};

パターンについてはパターンマッチングを参照してください。
ここではただの定数を使用しています。

switch式は、パターンに一致した式の評価値が式全体の評価値となります。
(パターンと式の組み合わせをswitch式アーム(switch expression arm)と言うそうです)
switch式それ自体も式なので、波括弧ブロックの末尾には式の終端(セミコロンなど)が必要です。
なお、それぞれのswitch式アームはコンマ(,)で区切りますが、一番最後の行のコンマはあってもなくてもどちらでも構いません。

switch式は全体の評価値が必要なので、必ずいずれかの式を実行し値を返す必要があります。
つまり、一致式の評価値が取り得る値を全てカバーした条件設定をする必要があります。
bool型ならば2種類しかないので簡単ですが、それ以外の型ではパターンマッチングがほぼ必須です。

以下はすべての範囲の値をカバーする例です。


bool b = true;
int n1 = b switch
{
    true => 1,
    false => 0,
};

int num = 1;
int n2 = num switch
{
    0 => 0,
    > 0 => 1,
    < 0 => -1
};

2番目の例はパターンマッチングを使用して、0なら0を、0より大きければ1を、0より小さければ-1を返します。

全ての条件に一致するパターン、つまりdefault句に相当するパターンは破棄パターン、もしくはvarパターンを使用します。


string s1 = 0 switch
{
    0 => "a",
    1 => "b",
    _ => "" //破棄パターン
};

string s2 = 0 switch
{
    0 => "a",
    1 => "b",
    var a => a.ToString() //varパターン
};

この例では一致式が0でも1でもない場合は最後の破棄パターン(varパターン)の式が実行されます。
switch式では上から順にパターンの一致判定が行われるので、破棄パターン(varパターン)は必ず最後に指定します。

switch式は式であるため、ほとんどの場所に記述可能です。
例えば式形式のメソッドの本体として記述できます。


static string M(int a) => a switch
{
    >= 100 => "100以上",
    >= 50 => "50以上",
    >= 0 => "0以上",
    _ => "0未満",
};

通常のメソッドの定義にも見えますが、本体は式なので末尾にセミコロン(;)が必要です。

パターンマッチング

パターンマッチングについてはパターンマッチングの項で改めて説明します。