C# 7.1
Ver. 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
名前空間)を使えるようになりました。
以下のいずれかのオーバーロードであればエントリーポイントとして認識されます。
static Task<int> Main()
static Task<int> Main(string[] args)
static Task Main()
static Task Main(string[] args)
詳しくは、「非同期Main」で説明します。
default 式
これまでも既定値を作るために、default(T)
という構文がありましたが、
型名T
の指定が煩雑でした。
特に、名前の長い型に対してdefault(T)
を使うと、かなりのうっとおしさがあります。
既定値を結構使って、かつ、名前が長い型というと、例えばCancellationToken
構造体(System.Threading
名前空間)とかです。
以下のようなコードを書いたりします。
static async Task DefaultExpression(CancellationToken c = default(CancellationToken))
{
while (c != default(CancellationToken) && !c.IsCancellationRequested)
{
await Task.Delay(1000);
Console.WriteLine(".");
}
}
これに対して、C# 7.1では、左辺(代入先)から推論できる場合に、(T)
を省略してdefault
だけで既定値を作れるようになりました。
例えば先ほどのコードは以下のように書き直せます。
static async Task DefaultExpression(CancellationToken c = default)
{
while (c != default && !c.IsCancellationRequested)
{
await Task.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ではコンパイル エラーになっていました。
static void M<T>(T x)
{
switch (x)
{
case int i:
break;
case string s:
break;
}
}
「T
をint
やstring
として処理できない」と言った旨のコンパイル エラーが出ます。
さらにいうと、以下のような需要が結構ありそうな場面でも、C# 7.0ではコンパイル エラーになりました。
class Base { }
class Derived1 : Base { }
class Derived2 : Base { }
class Derived3 : Base { }
// こういう、型制約付きのやつですら 7.0 ではダメだった
static void N<T>(T x)
where T : Base
{
switch (x)
{
case Derived1 d:
break;
case Derived2 d:
break;
case Derived3 d:
break;
}
}
C# 7.0でも、以下のように、as
演算子を使った場合にはちゃんとコンパイルできます。
型スイッチは、内部的にはas
演算子に展開される機能で、as
演算子にできて型スイッチにできないことがあるのは不自然です。
static void N<T>(T x)
where T : Base
{
{ var d = x as Derived1; if (d != null) { return; } }
{ var d = x as Derived2; if (d != null) { return; } }
{ var d = x as Derived3; if (d != null) { return; } }
}
そこで、C# 7.1では、上記コードのような、ジェネリックな型に対する型スイッチを使えるようになりました。 (新機能というよりは、仕様漏れ・バグ修正の類です。)
パターンマッチング(型スイッチ)自体の説明に関しては「型スイッチ」を参照してください。