.NET 6 Preview 1とか Visual Studio 16.9 正式版& 16.10 Preview 1とかが出ましたね。

というの、ライブ配信はしてたんですが。

その中で、今日は C# 10.0 候補で、すでに Visual Studio 16.10 にマージ済みの機能の紹介。 以下のようなコードがコンパイルできるようになっています。

int x;
(x, var y) = (1, "abc");

配信では言ってるんですが、 .NET 6 Preview 1 が出た時点で、コマンドライン (dotnet コマンド)ではコンパイルできていました。 「今回、.NET SDK と Visual Studio で2週間くらいリリースタイミング違うんですね」とか「Visual Studio は Ignite のために取っといたんですかね」とかいう感じ。

で、Visual Studio の方は、16.10 の方で「LangVersion preview」にした時だけ上記コードがコンパイルできます。

分解(C# 7.0)

分解という機能自体は C# 7.0 の頃に入っています。 以下のようなコード、どれも C# 7.0 として有効。

1つ目。() 内で変数宣言。

(int x, string y) = (1, "abc");

2つ目。これを型推論(var)で書いたもの。型推論してる点以外は1つ目のコードと同じ。コンパイラーの解釈結果は全く同じです。

(var x, var y) = (1, "abc");

3つ目。タプル変数宣言。頭に1個だけ var を書いて、複数の変数の宣言をまとめてやる構文。

var (x, y) = (1, "abc");

4つ目。既存の変数を使って分解。

int x;
string y;
(x, y) = (1, "abc");

混在分解(C# 10.0)

で、これの実装時点で、変数宣言と既存変数の混在についても検討はされていました。 「何か地雷を踏みそうで怖い」みたいな感じで「後でやる」扱い。

それが今回、16.10 Preview 1 でマージされました。 以下のコードが通ります。

int x;
(x, string y) = (1, "abc");

変数宣言には var も使えて、それが冒頭のコードになります。

int x;
(x, var y) = (1, "abc");

欲しいかと言われると微妙なライン… と感じますが、 実装負担がほとんどなかったみたいですね。

「あえてエラーにしてたけど、そのあえてエラーにする行を消すだけで動く」というレベルだったみたいで。 コミュニティ(C# チームの外の人)から「エラー行を消して、テストを足しといたよ」っていう pull request が出ていました。

pull request をみるに、式ステートメントと for の初期化式(1項目)中でだけ認めるみたいです。

int x;
 
// OK な例1
(x, string y1) = (1, "abc");
 
// OK な例2
for ((x, string y2) = (1, "abc"); false;)
{
}
 
// ダメな例1
var t = (x, string y3) = (1, "abc");
 
// ダメな例2
m(out (x, string y4));
void m(out (int, string) t) => t = (1, "abc");

ちなみに、コミュニティ貢献であってもレビューのコストは掛かるわけで、 この手の pull request が常にうまくいくわけではないんですが。 今回に関しては pull request 作者さんが元々 charplang/roslyn への貢献が大きい人なのと、 本当に「ほぼテストを足しただけ」レベルの修正だったからあっさりと通ったんじゃないかなという感じはします。