修飾子付きのシンプルなラムダ引数(Simple lambda parameters with modifiers)
C# 14では、引数の型を明示せずに、ラムダ式引数にref、scoped ref、ref readonly、in、outなどの修飾子を記述できるようになりました。
ラムダ式は、C# 2.0で導入された匿名メソッドを、よりシンプルに記述できるようにした構文です。匿名メソッドは、以下のようにdelegateキーワードで記述していました。
var f = delegate (int x) { return x * x; };
これをラムダ式で表現すると、以下のようになります。
var lambda = (int x) => x * x;
デリゲート型を定義し、ラムダ式を代入する場合、文脈から引数の型が明確な場合には、型の指定を省略できます。
delegate int Transformer(int x); Transformer t = x => x * x; // xはint型で戻り値もint型
もし、ref修飾子を付けて引数経由で結果を受け取りたい場合には、従来は型の省略はできず、明示的に型名とref修飾子を付ける必要がありました。
delegate void ViaTransformer(ref int x);
ViaTransformer vt = (ref int x) => { x *= x; }; // ref intが必要
C# 14では、この制約が緩和され、修飾子を付与する場合にも型の省略が可能になりました。
ViaTransformer vt2 = (ref x) => { x *= x; }; // intは省略できる
同様に、scoped ref、ref readonly、in、outについても型を省略できます。よりシンプルに、ラムダ式を記述できるようになったと言えるでしょう。
fieldキーワード(The field keyword)
C# 14では、バッキングフィールドの宣言なしでプロパティアクセサ本体を記述できるようになりました。
バッキングフィールドとは、プロパティ定義において、実際の値の格納に使われるフィールドです。バッキングとは「補助」といった意味で、以下のリストでは_messageがバッキングフィールドです。
private string _message; // バッキングフィールド
public string Message { get => _message; set => _message = value; }
自動実装プロパティでも、バッキングフィールドは暗黙的に宣言され、値の格納に使われます。
// バッキングフィールドは暗黙的に宣言される
public string Message { get; set; }
自動実装プロパティで済めばバッキングフィールドを明示的に記述する必要はありませんが、例えばセッタに独自のロジック(nullチェックして例外を発生させるなど)を組み込みたい場合には、バッキングフィールドを含めた通常のプロパティ宣言講文を使う必要があります。
private string _message;
public string Message {
get => _message;
set => _message = value ?? throw new ArgumentNullException(nameof(value));
}
せっかく自動実装プロパティがあるにもかかわらず、この構文はやや冗長です。そこで、C# 14ではバッキングフィールドをfieldキーワードで置き換え、かつ明示的な宣言が不要になりました。
上のコードは、以下のように書き替えられます。
// バッキングフィールド不要
public string Message {
get;
set => field = value ?? throw new ArgumentNullException(nameof(value));
}
fieldキーワードの登場で、フィールド名にfieldを使ってきたケースでは混乱が生じます。このため、フィールド名としてのfieldを使う場合にはthis.fieldのようにスコープを明確にしたり、@を前置してfieldを識別子として扱う必要があります。それでも記述が冗長になるので、新規のコードではfieldそのものを識別子として使用することを避けた方がよいでしょう。
