| リリース時期 | 2025/11 |
|---|---|
| 同世代技術 |
|
執筆予定: C# 14.0 トラッキング issue
field キーワード
field という文脈キーワードが追加されました。
プロパティの get/set の中に field と書くと、
バッキング フィールドを生成した上で、そのフィールドの読み書きができます。
例えば前述の例を field を使って書き直すと以下のようになります。
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
class FieldBackedProperties : INotifyPropertyChanged
{
// 遅延初期化: 最初のプロパティ アクセス時にインスタンスを生成。
public string X => field ??= "";
// set 側だけ null 許容(get 側で ?? で非 null 化)。
[AllowNull]
public string Y
{
get => field ?? "";
set;
}
// INotifyPropertyChanged の実装: get 側だけ素通し。
public string? Z
{
get;
set
{
if (field != value)
{
field = value;
PropertyChanged?.Invoke(this, new(nameof(Z)));
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
}
詳しくは「field キーワード」で説明します。
null 条件代入
代入演算の左側で ?. や ?[] を書くことで「null じゃないときだけ代入」ができるようになりました。
これを null 条件代入(null conditional assignment)といいます。
static void M(A? a)
{
// if (a != null) a.X = 10; とほぼ同じ。
a?.X = 10;
// if (a != null) a[0] = 10; とほぼ同じ。
a?[0] = 10;
// if (a != null) a.Event += () => { }; とほぼ同じ。
a?.Event += () => { };
}
class A
{
public int X { get; set; }
public int this[int index]
{
get => 0;
set { }
}
public event Action? Event;
}
詳しくは「null の取り扱い - null じゃないときだけ代入」で説明します。
First-class Span
Span<T>/ReadOnlySpan<T> 構造体を言語構文的に特別扱いするようなりました。
詳しくは「First-class Span」で説明します。
複合代入演算子のオーバーロード
複合代入演算子を直接オーバーロードできるようになりました。
record struct X(int Value)
{
public void operator +=(int value) => Value += value;
public void operator -=(int value) => Value -= value;
public void operator *=(int value) => Value *= value;
public void operator /=(int value) => Value /= value;
public void operator %=(int value) => Value %= value;
public void operator &=(int value) => Value &= value;
public void operator |=(int value) => Value |= value;
public void operator ^=(int value) => Value ^= value;
public void operator <<=(int value) => Value <<= value;
public void operator >>=(int value) => Value >>= value;
public void operator >>>=(int value) => Value >>>= value;
public void operator checked +=(int value) { checked { Value += value; }; }
public void operator checked -=(int value) { checked { Value += value; }; }
public void operator checked *=(int value) { checked { Value += value; }; }
public void operator checked /=(int value) { checked { Value += value; }; }
public void operator ++() => Value++;
public void operator --() => Value--;
public void operator checked ++() { checked { Value++; } }
public void operator checked --() { checked { Value--; } }
}
以前から二項演算子(+ など)のオーバーロードをすることで、それに対応する複合代入(+= など)ができていましたが、この実装だとコピーのコストが不可避でした。
複合代入演算子を直接オーバーロードすることでこのコストを削減できます。
詳しくは「複合代入演算子のオーバーロード」で説明します。
修飾子付きの引数の型名省略
ref や out などの修飾子が必須の引数でも、ラムダ式引数の型名を省略できるようになりました。
// C# 13 までは型名省略不可で、(string text, out int result) のように書く必要があった。
TryParse<int> m = (text, out result) => { result = 0; return true; };
delegate bool TryParse<T>(string text, out T result);
詳しくは「修飾子付きの引数の型名省略」で説明します。
その他
部分イベントと部分コンストラクター
部分プロパティ (C# 13)に続いて、 C# 14 ではイベントとコンストラクターも部分定義できるようになりました。
// 元コード(手書き想定)。
partial class PartialClass
{
// 部分イベント。
public partial event Action<int>? PartialEvent;
// 部分コンストラクター。
public partial PartialClass();
}
// コード生成で作ってもらう前提のコード。
partial class PartialClass
{
private Action<int>? _partialEvent;
public partial event Action<int>? PartialEvent
{
add => _partialEvent += value;
remove => _partialEvent -= value;
}
public partial PartialClass() { }
}
unbound な型に対する nameof
T<> みたいに型引数を埋めていないジェネリック型(これを unbound (未束縛)とか open (開きっぱなし) な型といいます)に対して nameof 演算子を使えるようになりました。
Console.WriteLine(nameof(List<>)); // "List"
Console.WriteLine(nameof(Dictionary<,>.Keys)); // "Keys"
Console.WriteLine(nameof(List<>.Enumerator.MoveNext)); // "MoveNext"
詳しくは「unbound な型に対する nameof」で説明します。
ファイル ベース実行
.NET 10 (C# 14 と同世代)で単独の .cs ファイルだけで C# プログラムを実行できるようになりました。
それに伴って、C# 的にも #! と #: (無視ディレクティブ)という機能が追加されています。
例えば以下のようなコードが書けて、
Unix 系シェルの shebang を書けたり、これまでであればプロジェクト(.csproj ファイル中)に書いていた設定の類を C# ソースコード中に書けるようになっています。
#!/usr/bin/env dotnet
#:sdk Microsoft.NET.Sdk.Web
var app = WebApplication.CreateBuilder(args).Build();
app.MapGet("/", () => "Hello World!");
app.Run();
詳しくは「ファイル ベース実行」で説明します。
