5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

What's new in C# 14

Last updated at Posted at 2025-03-12

3/6に.NET公式Xで、次期LTS版となる.NET 10 Preview1のリリースが発表され、なんか盛り上がってるぽい。
気になったので、C# 14の新機能を調べてみました。
間違ってたらご指摘いただけますと幸いです。

目次

fieldキーワード

fieldキーワードは、プロパティのアクセサ内でコンパイラが生成するバックフィールドにアクセスするためのコンテキストキーワードです。​これにより、明示的にバックフィールドを宣言することなく、プロパティのgetおよびsetアクセサ内で直接そのフィールドを操作できます。

従来、プロパティに対してカスタムのロジックを追加する際には、明示的にバックフィールドを宣言し、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));
}

このように、setアクセサ内でfieldキーワードを使用して、null値の設定を防ぐロジックを直接記述できます。

何がいいの?

  1. バックフィールドを明示せずにプロパティのロジックを記述できる
    上の例でいうと、_messageを記述する必要がなくなったことにより可読性が向上。自動プロパティとの統一性も保たれる。
  2. バックフィールドの名前衝突を防げる
    従来の方法では、開発者が_messag_valueなどのバックフィールド名を自分で管理する必要があった。
    しかし、C# 14のfieldは、コンパイラが自動生成するバックフィールドを参照するため、フィールド名の衝突を防ぐことができる。
  3. 保守性の向上
    ルールを直接プロパティに書けるので、保守しやすい。

要するに、fieldは「シンプルなコードでプロパティにロジックを追加したい」場合に特に有用!

fieldキーワードの導入により、既存のコードでfieldという名前のフィールドが存在する場合、名前の衝突が発生する可能性があります。​そのような場合、@fieldまたはthis.fieldとして参照することで曖昧さを解消できます。

補足:C# 13、,.NET 9でもプレビュー機能として使えるとのことです。

暗黙的なスパン変換

C# 14では、System.Span<T>およびSystem.ReadOnlySpan<T>に対する暗黙的な型変換が強化され、これらの型をより自然に操作できるようになりました。​これにより、パフォーマンス向上と安全性の確保が期待できます。

Span<int> numbers = new int[] { 1, 2, 3 };
ReadOnlySpan<int> readOnlyNumbers = numbers;

このように、T[]List<T>からSpan<T>への変換や、Span<T>からReadOnlySpan<T>への変換が容易になりました。

何がいいの?

  1. メモリ割り当てを減らし、パフォーマンスを向上
    Span<T>はヒープアロケーションを行わない構造体(struct)であり、配列やList<T>の一部を安全にスライス(部分参照)できる。
    C# 14以前は、明示的に.AsSpan()メソッドを呼ぶ必要があったが、C# 14では暗黙的に変換されるため、コードがシンプルになり、余計なメモリ割り当てを防ぐことができる。
  2. ReadOnlySpan<T>への変換が簡単になった
    C# 14では、Span<T>からReadOnlySpan<T>への変換が暗黙的に行われるため、明示的に.AsReadOnlySpan()メソッドを呼ぶ必要がなくなった。
  3. 文字列(string)からReadOnlySpan<char>への変換がスムーズに
    文字列(string)は不変(immutable)だが、C# 14ではReadOnlySpan<char>に暗黙的に変換できるようになった。
string text = "Hello, World!";
ReadOnlySpan<char> span = text;  // 暗黙的に変換される

nameof演算子での未バインドのジェネリック型のサポート

C# 14では、nameof演算子がジェネリック型のオープン型(未バインド型)をサポートするようになりました。​これにより、ジェネリック型の型引数を指定せずに、その型名を取得することが可能となりました。

Console.WriteLine(nameof(List<>));  // 出力: List

C# 14 より前のバージョンでは、nameof 演算子にジェネリック型を渡す際、クローズド型(型引数が指定された型)のみがサポートされていました。​つまり、型引数を具体的に指定しなければなりませんでした。

Console.WriteLine(nameof(List<int>));  // 出力: List

何がいいの?

型引数に依存せず、より柔軟なコードが書ける

修飾子付きラムダ式パラメーターの単純化

C# 14 では、ラムダ式のパラメーターにscopedrefinoutrefreadonlyを 型指定なしで追加することが可能になりました。

delegate bool TryParse<T>(string text, out T result);

TryParse<int> parse1 = (text, out result) => Int32.TryParse(text, out result);

C# 13以前では、ラムダ式のパラメーターにoutなどの修飾子を付ける場合、パラメーターの型を明示的に記述する必要がありました。

TryParse<int> parse2 = (string text, out int result) => Int32.TryParse(text, out result);

params修飾子だけは 型を省略できません。

// C# 14でもエラーになる
Action printAll = (params values) => Console.WriteLine(string.Join(", ", values));

// 型を明示すればOK
Action<string[]> printAll = (params string[] values) => Console.WriteLine(string.Join(", ", values));

参考

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?