C# 7.1
| リリース時期 | 2017/8 |
|---|---|
| 同世代技術 |
|
| 要約・目玉機能 |
|
2017年8月、すなわち、C# 7.0のリリース(2017年2月)から半年足らずで C# 7.1 がリリースされました。
C# 7.0の頃から、目標としては C# のリリース サイクルの短縮を考えていました。多くの機能を2・3年に1度一気にリリースするよりも、細かく出せるものに関しては短いリリース サイクルで出したいという意図です。今回、(実質的に※)初の「マイナー バージョンアップ」となる C# 7.1 が誕生しました。
(※ 一応、C# 1.1があったんですが、ほとんど使われない機能が2つ追加されただけなので、1.1があったこと自体あまり認知されていないものです。)
C# 7.1 は、Visual Studio 2017のリリース時期に間に合わなかった C# 7.0 の積み残しと言った感じの、小さい機能が4つほど追加されています。
非同期Main
Mainメソッドの戻り値にTaskクラス(System.Threading.Tasks名前空間)を使えるようになりました。以下のいずれかのオーバーロードであればエントリーポイントとして認識されます。
staticTask<int> Main()staticTask<int> Main(string[] args)staticTask Main()staticTask Main(string[] args)詳しくは、「非同期Main」で説明します。
default 式
これまでも既定値を作るために、default(T)という構文がありましたが、型名Tの指定が煩雑でした。特に、名前の長い型に対してdefault(T)を使うと、かなりのうっとおしさがあります。
既定値を結構使って、かつ、名前が長い型というと、例えばCancellationToken構造体(System.Threading名前空間)とかです。以下のようなコードを書いたりします。
staticasyncTask DefaultExpression(CancellationToken c =default(CancellationToken)){while (c !=default(CancellationToken) && !c.IsCancellationRequested) {awaitTask.Delay(1000);Console.WriteLine("."); }}これに対して、C# 7.1では、左辺(代入先)から推論できる場合に、(T)を省略してdefaultだけで既定値を作れるようになりました。例えば先ほどのコードは以下のように書き直せます。
staticasyncTask DefaultExpression(CancellationToken c =default){while (c !=default && !c.IsCancellationRequested) {awaitTask.Delay(1000);Console.WriteLine("."); }}既定値自体や、default(T)の説明は「既定値」を参照してください。
タプル要素名の推論
タプルの要素名が、タプル構築時に渡した変数から推論できるようになりました。例えば以下のように、(x, y) と書くだけで、1要素目にx、2要素目にy という名前が付きます。(これまでだと、(x: x, y: y) と書く必要があった。)
var x = 1;var y = 2;var t = (x, y);// C# 7.0。t の要素には名前が付かないConsole.WriteLine(t.Item1);Console.WriteLine(t.Item2);// C# 7.1。(x, y) で (x: x, y: y) 扱い// t の要素に x, y という名前が付くConsole.WriteLine(t.x);Console.WriteLine(t.y);詳しくは「タプル」で説明します。
ジェネリック型に対するパターン マッチング(型スイッチ)
C# 7.0でisやswitchで型を見ての分岐ができるようになりました。しかし、ジェネリクスが絡む場合、例えば以下のようなコードはC# 7.0ではコンパイル エラーになっていました。
staticvoid M<T>(T x){switch (x) {caseint i:break;casestring s:break; }}「Tをintやstringとして処理できない」と言った旨のコンパイル エラーが出ます。
さらにいうと、以下のような需要が結構ありそうな場面でも、C# 7.0ではコンパイル エラーになりました。
classBase { }classDerived1 :Base { }classDerived2 :Base { }classDerived3 :Base { }// こういう、型制約付きのやつですら 7.0 ではダメだったstaticvoid N<T>(T x)whereT :Base{switch (x) {caseDerived1 d:break;caseDerived2 d:break;caseDerived3 d:break; }}C# 7.0でも、以下のように、as演算子を使った場合にはちゃんとコンパイルできます。型スイッチは、内部的にはas演算子に展開される機能で、as演算子にできて型スイッチにできないことがあるのは不自然です。
staticvoid N<T>(T x)whereT :Base{ {var d = xasDerived1;if (d !=null) {return; } } {var d = xasDerived2;if (d !=null) {return; } } {var d = xasDerived3;if (d !=null) {return; } }}そこで、C# 7.1では、上記コードのような、ジェネリックな型に対する型スイッチを使えるようになりました。(新機能というよりは、仕様漏れ・バグ修正の類です。)
パターンマッチング(型スイッチ)自体の説明に関しては「型スイッチ」を参照してください。
