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>
あぱしょに