C# 8.0のswitch式

switch式

C#のswitchが、C# 8.0から式で使えるようになってます。いいですね。

良い例が思い浮かばないのが申し訳ないですが、このようなEnumがあるとします。

public enum DayOfWeek
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
}

ある日付の曜日を日本語で表示するためのswitchを使用するとします。従来はこのように書いていました。

var dow_eng = DateTime.Today.DayOfWeek;
var dow_jpn = "";

switch ((DayOfWeek)dow_eng)
{
    case DayOfWeek.Sunday:
        dow_jpn = "日曜日";
        break;
    case DayOfWeek.Monday:
        dow_jpn = "月曜日";
        break;
    case DayOfWeek.Tuesday:
        dow_jpn = "火曜日";
        break;
    case DayOfWeek.Wednesday:
        dow_jpn = "水曜日";
        break;
    case DayOfWeek.Thursday:
        dow_jpn = "木曜日";
        break;
    case DayOfWeek.Friday:
        dow_jpn = "金曜日";
        break;
    case DayOfWeek.Saturday:
        dow_jpn = "土曜日";
        break;
    default:
        dow_jpn = "エラー";
        break;
}

Console.Write(dow_jpn);

なっが~~。これいちいちcaseとかdefaultとかbreakとかだらだらと書かなきゃいけなくて、すごく面倒ですよね。

これがC# 8.0ではこう書けます。

var dow_eng = DateTime.Today.DayOfWeek;
var dow_jpn = (DayOfWeek)dow_eng switch
{
    DayOfWeek.Sunday => "日曜日",
    DayOfWeek.Monday => "月曜日",
    DayOfWeek.Tuesday => "火曜日",
    DayOfWeek.Wednesday => "水曜日",
    DayOfWeek.Thursday => "木曜日",
    DayOfWeek.Friday => "金曜日",
    DayOfWeek.Saturday => "土曜日",
    _ => "エラー",
};

Console.Write(dow_jpn);

すっきりしましたね。特徴としてはswitch式なので、それ自体が文字列を返してくれます。長ったらしくcaseとかを書かずに済むのはとても良いですね。

defaultに当たる処理は_とマッチさせます。

_が使われている場合は無視される

C#はstringswitchに使用できます。その場合、caseには変数(定数)も使用できます。

では_が既に変数(定数)として使用されている場合はどうなるでしょうか。

var lastName = "八千崎";

const string _ = "雪村";
const string KuraueHinata_last = "倉上";
const string AobaKokona_last = "青羽";
const string SaitoKaede_last = "斎藤";
const string KurosakiHonoka_last = "黒崎";

var firstName = lastName switch
{
    KuraueHinata_last => "ひなた",
    AobaKokona_last => "ここな",
    SaitoKaede_last => "かえで",
    KurosakiHonoka_last => "ほのか",
    _ => "あおい",
};

Console.Write(firstName);
// 出力結果:あおい

なんと、定数としての_とはマッチせずに、defaultのキーワードとしての_としてマッチしてしまいました。この結果、八千崎という人があおいちゃんと認識されてしまいました。これはまずい!

まぁまずないとは思いますが、_という変数(定数)はうまくマッチングできないので使用を控えましょう。個人的にはout引数でも特別な意味のあるキーワードなので_という変数などは宣言できないようにしてほしいのですが、まぁ後方互換性とかもあるのでね、仕方ないですね…。

あおいちゃんとマッチングさせたくない場合は、面倒くさがらず

var lastName = "八千崎";

const string AoiYukimura_last = "雪村";
const string KuraueHinata_last = "倉上";
const string AobaKokona_last = "青羽";
const string SaitoKaede_last = "斎藤";
const string KurosakiHonoka_last = "黒崎";

var firstName = lastName switch
{
    AoiYukimura_last => "あおい",
    KuraueHinata_last => "ひなた",
    AobaKokona_last => "ここな",
    SaitoKaede_last => "かえで",
    KurosakiHonoka_last => "ほのか",
    _ => "そんな子おらん",
};

Console.Write(firstName);
// 出力結果:そんな子おらん

としましょう。

複数caseとのマッチは不可

ただし、複数のcaseとマッチさせることはできません。

具体的には、平日か休日かを判定したい場合、従来は

var dow_eng = DateTime.Today.DayOfWeek;
var workdayOrHoliday = "";

switch ((DayOfWeek)dow_eng)
{
    case DayOfWeek.Monday:
    case DayOfWeek.Tuesday:
    case DayOfWeek.Wednesday:
    case DayOfWeek.Thursday:
    case DayOfWeek.Friday:
        workdayOrHoliday = "平日";
        break;
    case DayOfWeek.Saturday:
    case DayOfWeek.Sunday:
        workdayOrHoliday = "休日";
        break;
    default:
        workdayOrHoliday = "エラー";
        break;
}

Console.Write(workdayOrHoliday);

この様に、月~金は平日、土・日は休日とまとめて指定できたのですが、新しいswitch式ではそれができません。

var dow_eng = DateTime.Today.DayOfWeek;
var workdayOrHoliday = (DayOfWeek)dow_eng switch
{
    DayOfWeek.Sunday  => "休日",
    DayOfWeek.Monday => "平日",
    DayOfWeek.Tuesday => "平日",
    DayOfWeek.Wednesday => "平日",
    DayOfWeek.Thursday => "平日",
    DayOfWeek.Friday => "平日",
    DayOfWeek.Saturday => "休日",
    _ => "エラー",
};

Console.Write(workdayOrHoliday);

と書くしかないんですね。これは嫌ですね。個人的には以下のような感じで書ければなと思っています。このコードは動きません。

var dow_eng = DateTime.Today.DayOfWeek;
var workdayOrHoliday = (DayOfWeek)dow_eng switch
{
    DayOfWeek.Monday | DayOfWeek.Tuesday | DayOfWeek.Wednesday | DayOfWeek.Thursday | DayOfWeek.Friday => "平日",
    DayOfWeek.Sunday | DayOfWeek.Saturday  => "休日",
    _ => "エラー",
};

Console.Write(workdayOrHoliday);

今後拡張されるかもしれないので、楽しみに待とうと思います。

ということでC# 8.0におけるswitch式の備忘録でした。

おまけ

まぁ例が悪かったのでアレなんですけど、単純に日本語の曜日を取得するだけなら

var culture_jpn = CultureInfo.GetCultureInfo("ja-JP");
var dow_jpn = DateTime.Today.ToString("dddd", culture_jpn);
Console.Write(dow_jpn);

上記でできます。実行環境が日本語カルチャの設定になっているなら、カルチャの指定すら不要です。

// 実行環境が日本カルチャの場合
var dow_jpn = DateTime.Today.ToString("dddd");
Console.Write(dow_jpn);