C#7時代の型変換
C#7.0
から、型変換において、型スイッチ 型パターンという便利な書き方ができるようになりました。
コメントで型スイッチは古い呼び方と教えていただきました!
pattern-matching
https://docs.microsoft.com/ja-jp/dotnet/csharp/pattern-matching
こちらの記事様を参考にさせていただきました。
is、switch の拡張 (型スイッチ) - C# によるプログラミング
https://ufcpp.net/study/csharp/datatype/typeswitch/
この記事では簡単な使用例を示します。
is/as演算子
そのまえに、is/as演算子
を使った従来の型変換について超簡単におさらい。
is演算子
変数名で指定したクラスにダウンキャスト可能かどうかを調べる。
ダウンキャストできるか否かが、true/false
で返される。
構文 : 変数名 is クラス名
Object obj = "hoge";
String str = (String)obj;
Console.WriteLine(obj is str); // true
as演算子
is演算子
のように前もって診断しなくても安全にダウンキャストできる。ダウンキャストを実行して、ダウンキャスト不可の場合はnull
を返す。
構文 : 変数名 as クラス名
Object obj = "hoge";
String str = obj as String;
Console.WriteLine(str == null); // false
使い分け
もし、ダウンキャスト判定するだけなら、is演算子
だけで十分です。
Object obj = "hoge";
if (obj is string) Console.WriteLine("Do something!");
ただし、判定した上で、さらにダウンキャストもしたい場合。is演算子
を使うと以下のような二重処理のコードになってしまい、なんかあんまり良くない感じです。
Object obj = "hoge";
// 処理[1]->判定
if (obj is string) {
// 処理[2]->キャスト
var s = (string)obj;
}
この場合、as演算子
を使った方がスマートです。
Object obj = "hoge";
var s = obj as string;
if (s != null) Console.WriteLine("Do something!");
型スイッチ 型パターン (C#7.0)
やっと本題です。
C#7では、上記のis演算子
が拡張され「ダウンキャストできるかどうかの判定」と「新しい変数の定義」が同時にできるようになりました。これを型スイッチ 型パターンといい、さらにスマートな記述ができるようになりました。
ダウンキャスト可能ならtrue
が返り、ダウンキャストが実行され変数が定義されます。
構文 : 変数 is 型 変数名
Object obj = "hoge";
if (obj is string str) Console.WriteLine("Do something!");
switch文の拡張 (C#7.0)
型スイッチはswitch文
でも使えます。
caseの後ろに型
も書けるようになりました。
構文 : case 型 変数名:
Object obj = "hoge";
switch (obj) {
case int x:
Console.WriteLine(x);
break;
case string str: // <- このcaseにマッチする
Console.WriteLine(str); // hoge
break;
}
whenキーワード
また、when
による条件フィルターをかけることもできます。
構文 : case 型 変数名 when 条件式
Object obj = "hoge";
switch (obj) {
case int x:
Console.WriteLine(x);
break;
case string str when (str.Length == 4):
Console.WriteLine(str); // hoge
break;
}
ジェネリックな型スイッチ (C#7.1)
さらにC#は進化を止めず、C#7.1では、ジェネリック型の型スイッチが使えるようになりました。つまり、ジェネリック型の引数に対してパターンマッチングすることができます。かなり便利な機能だと思うのですが、C#7.0まではこれをやるとコンパイルエラーとなります。
switch (x) {
case int i:
Console.WriteLine(i);
break;
case string s:
Console.WriteLine(s);
break;
default:
Console.WriteLine("not match");
break;
}
// C#7.0まではコンパイルエラー
おわり