2025/12/19 / Unity

C#14の新機能の解説

C#14で導入された注目の機能を実例を交えてわかりやすく解説します。

unity csharp

こんにちは!パン君です。

今回は先月末に公開された C#14 のドキュメントからいくつか機能をピックアップして紹介しようと思います。
公式はこちら
C# 14 の新機能learn.microsoft.comC# 14 の新機能C# 14 の新機能の概要について説明します。 C# 14 には .NET 10 が付属しています。

C#14新機能

field キーワード

よくフィールドとプロパティを利用して下記のような記述を多様する方がいるかと思います。 これの目的はご存知の通り カプセル化が主な目的です。
これが今回の新機能で下記のように記述が可能になりました。

Csharp
// before
private string m_foo;
public string Foo
{
    get => m_foo;
    private set => m_foo = value; 
    // nullチェックを入れたかったら 
    // ?? throw new ArgumentNullException(nameof(value))
}

// after
public string Foo
{
    get;
    set => field = value;
} 

IntelliSenseがあるIDE利用者とかは m_ と入力して予測補完させる人とか多いはずなので、正直コードの組み方次第な機能ですね
Regionとかでくくったり、可読性など気にしていたり、
IntelliSense前提のコーディングをしていない人とかなら良いのかも?

まぁそもそもちゃんとしたコード規約の元作られているプロジェクトでの作業前提ではありますが、、、  

一応このシンボルと重複した命名があるときの対処法もドキュメントは追記してくれています。
がしかし、それより先にfieldっていう命名を見つけたらgit blameで特定してその人を警戒するようにしましょう。

fieldという名前のシンボルを含む型のコードを読み取る場合、破壊的変更や混乱が生じる可能性があります。
@fieldまたはthis.fieldを使用して、field キーワードと識別子の間であいまいさを解消したり、
現在のfieldシンボルの名前を変更して区別を深めることができます。

C# 14 の新機能learn.microsoft.comC# 14 の新機能C# 14 の新機能の概要について説明します。 C# 14 には .NET 10 が付属しています。

拡張メンバー

よく引き数に this ClassName valueName と記述するあれですね

Csharp
public class Foo 
{
    public int hoge = 1;
}

// before
public static class FooExtensions
{
    public static int BeforeExtension(this Foo foo) => foo.hoge;
}

// after
public static class FooExtensions
{
    extension(Foo foo)
    {
        public int AfterExtension() => foo.hoge;
    }
}

メリットは

  • 毎回引き数にインスタンスを渡す場所の明記がいらなくなった
  • extension ブロック内に記述すればいいので、視覚的に優しくなった
  • 拡張プロパティも宣言可能
  • 拡張オペレーターの宣言も可能

他詳細は下記の公式参照
C# 14 の新機能learn.microsoft.comC# 14 の新機能C# 14 の新機能の概要について説明します。 C# 14 には .NET 10 が付属しています。

Null 条件付き割り当て

Csharp
public Class Hoge
{
    public string? Name = { get; set; } = null;
}

void string GetName() => "Pankun";

void Foo(Hoge? hoge)
{
    // before
    if(hoge is not null) // Null check can be simplified (IDE0031)
        hoge.Name = GetName();
      
    // after  
    hoge?.Name = getName();  
}

メリットは

  • ネスト節約
  • 上に続いて可読性向上

Partialメンバー

Csharp
// Foo.cs
public partial class Foo
{
    // コンストラクター実装
    public partial Foo()
    {
        Hoge();
    }
    
    // メンバ関数追加
    private partial void Hoge() => Console.WriteLine("Partial Hoge");
}

// Foo.members.cs
public partial class Foo
{
    // ここで宣言だけ追加が可能
    // コンストラクター対応
    // staticは対応していません
    public partial Foo(); // Success
    private partial void Hoge(); // Success
}

これで 「これ定義無いけどなんで呼べているんだ?」 とならなくて済みます。

nameofが未バインドジェネリック型に対応

Csharp
public static void ShowExample()
{
    // Before
    Console.WriteLine(nameof(List<int>)); // List<int>
    
    // After
    // nameof する引数はバインドされていないジェネリック型にすることができます。
    Console.WriteLine(nameof(List<>)); // List
    // NOTE: Use unbound generic type (IDE0340)
    Console.WriteLine(nameof(List<int>)); // List<int> 
}

これにより幅広く判定が取れるようになりました。 (型引き数を埋めていないジェネリック型を unbound(未束縛) って言ったりすることを今回初めて知りました。)

.NET 10

他にもC#14で追加された機能はあるのですが、
.NET側にもいくつか昨日が追加されているのでそちらについても少しふれておきます。

詳しくは下記参照
.NET 10 の新機能learn.microsoft.com.NET 10 の新機能ランタイム、ライブラリ、SDK 用に .NET 10 で導入された新機能について説明します。 ASP.NET Core など、他の領域の新機能へのリンクも参照してください。

shebang

下記のように記載することでファイルベースでスクリプトを実行できるようになりました。
これによりプロジェクトを作成したり、Mainメソッドを作成したりなどなどする必要がなくなります。

Csharp
#!/usr/bin/env -S dotnet run
Console.WriteLine("Hoge");

他にもBlazorでで改善があったらしいのです。

まとめ

まだプレビュー版ですがプライベートのコーディングではかなり使用頻度に期待できる機能が追加された印象です。
是非使っていきたいですね。

← Zed IDE setti…← ブログ一覧へ戻るブログのCSSにコードブロ… →