Visual Studio 16.1 のリリースと、16.2 の Preview 1 が来ていますね。
16.1
16.1 の方は、こないだの Preview 3からそんなに変わってなくて、割かし「リリースされました」という感じ。
C# 8.0 的には、
- Rangesは たぶん、今の挙動で確定
-
switch
式- 優先度が
+
よりも上になってる - Target-typed switch は 8.0 候補になってて、かつ、未実装
- 優先度が
-
非同期イテレーター
EnumeratorCancellation
属性を付けた引数にCancellationToken
が渡るように- 変更が確定していて、16.2 Preview 1 ですでに挙動が違う(後述)
- インターフェイスのデフォルト実装も 16.2 Preview 1 で変更あり(後述)
- null 許容参照型は相変わらず作業真っ最中
という感じ。
16.2 Preview 1
IDE 的には以下のようなものが増えてるみたいです。
- プロジェクトの新規作成で、作成したいアプリのタイプで検索できるように
- テスト エクスプローラーがだいぶ見やすく
あと、Developer PowerShell (開発ツールがらみの環境変数とかパスが通った状態の PowerShell)が追加されたみたいです。 これまでもあった Developer Command Prompt の PowerShell 版。
ちょっと C# コンパイラーに致命的なバグがありそうなので注意。
安全な stackalloc
を使うと不正なコードを生成して、プログラムが起動できなくなります。
(正確に言うと、stackalloc
を書いたメソッドを呼んだ瞬間、InvalidProgram
例外発生。)
修正済みっぽいんですけど、16.2 Preview 1 には反映されていない状態。
C# 8.0 的には、16.1 の方と以下の差があります。
- 非同期イテレーターの
EnumeratorCancellation
属性の仕様変更 base(T)
削除- stackalloc in nested expressions の追加
あと、null許容参照型をプロジェクト単位で有効化するための設定も、<Nullable>enable</Nullable>
に変わっています(16.1 までは NullableContextOptions
)。
非同期イテレーターの仕様変更
X(ct1).WithCancellation(ct2)
みたいなのを書いたときの挙動が変わります。
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var c1 = new CancellationTokenSource();
var c2 = new CancellationTokenSource();
// キャンセルなし
await foreach (var x in X()) ;
// AscynEnumerable 生成時に c1 が渡る
await foreach (var x in X(c1.Token)) ;
// GetAsyncEnumerator 時に c2 が渡る
await foreach (var x in X().WithCancellation(c2.Token)) ;
// 旧挙動: c2 だけが渡る
// 新挙動: c1, c2 の両方が渡る。内部で CreateLinkedTokenSource
await foreach (var x in X(c1.Token).WithCancellation(c2.Token)) ;
}
// 新挙動: EnumeratorCancellation 属性付きの引数は1個に限る
static async IAsyncEnumerable<int> X([EnumeratorCancellation]CancellationToken ct = default)
{
await Task.Yield();
yield break;
}
}
base(T) 削除
base(T) アクセス、いったん取りやめになりました。 (書いた記事どうしよう… 消すか、「今後入る予定です」に変えるか…)
C# コンパイラーだけでできる実装方法だと不満だそうで、 .NET Core ランタイム側も合せて修正変更したいそうです。 結果的に C# 8.0 には間に合わず、ランタイム修正ありなものをマイナー リリースするとは思えないので 9.0 以降での実装になります。
stackalloc in nested expressions
式のど真ん中に stackalloc
を書けるようになりました。
using System;
using System.Threading.Tasks;
class Program
{
static int M(Span<int> span) => 0;
static void Main()
{
// 引数にも書けたり
M(stackalloc int[1]);
// 式のどこにでも書ける
if (stackalloc int[1] == stackalloc int[1]) { }
}
// フィールド初期化子内にも書けたり
int x = M(stackalloc int[1]);
static async Task Async()
{
// 式中に書くなら、非同期メソッド内でも stackalloc が書ける
M(stackalloc int[1]);
await Task.Yield();
}
}
ぶっちゃけ、再帰パターンのついでだそうです。
再帰パターンの導入で参照として返せるものの判定が複雑になったらしく、
ちゃんとした判定に書き換えたらついでに stackalloc
を書ける場所も増えたとのこと。