tag:crieit.net,2005:https://crieit.net/tags/switch/feed 「switch」の記事 - Crieit Crieitでタグ「switch」に投稿された最近の記事 2021-05-08T22:36:30+09:00 https://crieit.net/tags/switch/feed tag:crieit.net,2005:PublicArticle/17072 2021-05-08T22:36:30+09:00 2021-05-08T22:36:30+09:00 https://crieit.net/posts/switch-expression-in-csharp-8 C# 8.0のswitch式 <h1 id="switch式"><a href="#switch%E5%BC%8F">switch式</a></h1> <p>C#の<code>switch</code>が、C# 8.0から式で使えるようになってます。いいですね。</p> <p>良い例が思い浮かばないのが申し訳ないですが、このような<code>Enum</code>があるとします。</p> <pre><code class="csharp">public enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, } </code></pre> <p>ある日付の曜日を日本語で表示するための<code>switch</code>を使用するとします。従来はこのように書いていました。</p> <pre><code class="csharp">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); </code></pre> <p>なっが~~。これいちいち<code>case</code>とか<code>default</code>とか<code>break</code>とかだらだらと書かなきゃいけなくて、すごく面倒ですよね。</p> <p>これがC# 8.0ではこう書けます。</p> <pre><code class="csharp">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); </code></pre> <p>すっきりしましたね。特徴としては<code>switch式</code>なので、それ自体が文字列を返してくれます。長ったらしく<code>case</code>とかを書かずに済むのはとても良いですね。</p> <p><code>default</code>に当たる処理は<code>_</code>とマッチさせます。</p> <h2><code>_</code>が使われている場合は無視される</h2> <p>C#は<code>string</code>も<code>switch</code>に使用できます。その場合、<code>case</code>には変数(定数)も使用できます。</p> <p>では<code>_</code>が既に変数(定数)として使用されている場合はどうなるでしょうか。</p> <pre><code class="csharp">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); // 出力結果:あおい </code></pre> <p>なんと、定数としての<code>_</code>とはマッチせずに、<code>default</code>のキーワードとしての<code>_</code>としてマッチしてしまいました。この結果、八千崎という人があおいちゃんと認識されてしまいました。これはまずい!</p> <p>まぁまずないとは思いますが、<code>_</code>という変数(定数)はうまくマッチングできないので使用を控えましょう。個人的には<code>out</code>引数でも特別な意味のあるキーワードなので<code>_</code>という変数などは宣言できないようにしてほしいのですが、まぁ後方互換性とかもあるのでね、仕方ないですね…。</p> <p>あおいちゃんとマッチングさせたくない場合は、面倒くさがらず</p> <pre><code class="csharp">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); // 出力結果:そんな子おらん </code></pre> <p>としましょう。</p> <h1>複数<code>case</code>とのマッチは不可</h1> <p>ただし、複数の<code>case</code>とマッチさせることはできません。</p> <p>具体的には、平日か休日かを判定したい場合、従来は</p> <pre><code class="csharp">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); </code></pre> <p>この様に、月~金は平日、土・日は休日とまとめて指定できたのですが、新しい<code>switch式</code>ではそれができません。</p> <pre><code class="csharp">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); </code></pre> <p>と書くしかないんですね。これは嫌ですね。個人的には以下のような感じで書ければなと思っています。このコードは動きません。</p> <pre><code class="csharp">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); </code></pre> <p>今後拡張されるかもしれないので、楽しみに待とうと思います。</p> <p>ということでC# 8.0における<code>switch式</code>の備忘録でした。</p> <h1 id="おまけ"><a href="#%E3%81%8A%E3%81%BE%E3%81%91">おまけ</a></h1> <p>まぁ例が悪かったのでアレなんですけど、単純に日本語の曜日を取得するだけなら</p> <pre><code class="csharp">var culture_jpn = CultureInfo.GetCultureInfo("ja-JP"); var dow_jpn = DateTime.Today.ToString("dddd", culture_jpn); Console.Write(dow_jpn); </code></pre> <p>上記でできます。実行環境が日本語カルチャの設定になっているなら、カルチャの指定すら不要です。</p> <pre><code class="csharp">// 実行環境が日本カルチャの場合 var dow_jpn = DateTime.Today.ToString("dddd"); Console.Write(dow_jpn); </code></pre> あぱしょに