.NET 10 (C# 14) の新機能をまとめる
概要
[.NET 10 の新機能] https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/overview から、抜粋します。詳細はリンク先を参照してください。
本記事のコードは https://github.com/Kuroki-g/kuroki-g-public-zenn-code/tree/main/articles/dotnet10-feature にまとめてあります。
.NET ライブラリ
以下の内容をコードに起こしました。一部は省略しています。
- [.NET 10 用 .NET ライブラリの新機能] https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/libraries
グローバリゼーションと日付/時刻
文字列比較の数値の順序付け
StringComparer numericStringComparer = StringComparer.Create(
System.Globalization.CultureInfo.CurrentCulture,
System.Globalization.CompareOptions.NumericOrdering // NumericOrderingオプションが追加されました。
);
Console.WriteLine(numericStringComparer.Equals("02", "2")); // これはTrueと判定されます。
var sorted = new[] { "Windows XP", "Windows 10", "Windows 8", "Windows 11" }.Order(numericStringComparer);
// 10、11の数字が考慮され、以下の順番で出力されます:
// Windows 8
// Windows 10
// Windows 11
// Windows XP
foreach (string os in sorted)
{
Console.WriteLine(os);
}
HashSet<string> set = new(numericStringComparer) { "007", "07", "7" };
Console.WriteLine(string.Join(",", set.ToArray())); // Output: 007 <- 順番が考慮されます。
Console.WriteLine(set.Contains("7")); // Output: True
HashSet<string> set2 = new(numericStringComparer) { "7", "007", "07", };
Console.WriteLine(string.Join(",", set2.ToArray())); // Output: 7 <- 順番が考慮されます。
Console.WriteLine(set2.Contains("007")); // Output: True
シリアル化
JSON プロパティの重複を禁止するオプション
record MyRecord(int Value);
string json = """{ "Value": 1, "Value": -1 }""";
Console.WriteLine(JsonSerializer.Deserialize<MyRecord>(json)?.Value); // -1
// AllowDuplicatePropertiesを指定すると、例外となります。
JsonSerializerOptions options = new() { AllowDuplicateProperties = false };
try
{
// JsonObject、Dictionary<string, int>でも同様にJsonExceptionとなります。
JsonSerializer.Deserialize<MyRecord>(json, options);
}
catch (JsonException ex)
{
Console.WriteLine(ex.Message);
}
// JsonDocumentでも同様に、AllowDuplicatePropertiesの設定が可能です。
JsonDocumentOptions docOptions = new() { AllowDuplicateProperties = false };
try
{
JsonDocument.Parse(json, docOptions);
}
catch (JsonException ex)
{
Console.WriteLine(ex.Message);
}
厳密な JSON シリアル化オプション
string json = """{ "Value": 1, "Value": -1 }""";
JsonSerializer.Deserialize<MyRecord>(json, JsonSerializerOptions.Strict);
// JsonSerializerOptions.Strict プリセットが追加されました。
// これは、以下のものに等しいです。
// JsonUnmappedMemberHandling.Disallow
// + JsonSerializerOptions.AllowDuplicateProperties = false
// + case sensitive (大文字と小文字の区別)
// + JsonSerializerOptions.RespectNullableAnnotations
// + JsonSerializerOptions.RespectRequiredConstructorParameters
// <https://github.com/dotnet/dotnet/blob/89c8f6a112d37d2ea8b77821e56d170a1bccdc5a/src/runtime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs#L180>
その他
他、複数の追加があります。
- System.Numerics
- オプションの検証
- 診断
- ZIP ファイル
- Windows プロセス管理
- WebSocket の機能強化
- TLS の機能強化
詳細は、[.NET 10 用 .NET ライブラリの新機能] https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/libraries を参照してください。
C# 14 の新機能
以下の内容をコードに起こしました。一部は省略しています。
- [.NET 10の新機能] https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/overview
- [C# 14 の新機能] https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14
拡張メンバー
namespace Dotnet10Feature.Extensions;
/// <summary>
/// 拡張メンバー
/// C# 14 では、 拡張メンバーを定義するための新しい構文が追加されています。
/// </summary>
/// <see href="https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14#extension-members"/>
public static class Enumerable
{
// 新しく、extensionブロックを用いて拡張メンバーを宣言することができるようになりました。
// Extension block
// https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/extension-methods#declare-extension-members
extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>
{
// 新しく拡張プロパティの宣言ができるようになりました:
public bool IsEmpty => !source.Any();
// 拡張メソッドの宣言をextensionブロックに書くことができます:
public IEnumerable<TSource> Where(Func<TSource, bool> predicate)
{
throw new NotImplementedException();
}
}
// C# 14より前の場合、拡張プロパティはないのでメソッドで宣言する必要があります。
public static bool BeforeC14IsEmpty<TSource>(this IEnumerable<TSource> source)
=> !source.Any();
// 既存のC# 14より前のバージョンの拡張メソッドの宣言はこれまで通りです。
public static IEnumerable<TSource> BeforeC14Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
throw new NotImplementedException();
}
// 静的メンバー + operatorのみの場合には、レシーバー型のみの、extensionブロックで表現することもできる。
extension<TSource>(IEnumerable<TSource>)
{
// static拡張メソッド:
public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second)
{
throw new NotImplementedException();
}
// static拡張プロパティが定義可能です:
public static IEnumerable<TSource> Identity => System.Linq.Enumerable.Empty<TSource>();
// ユーザー定義のoperatorの定義ができるようになりました:
// NOTE: [Extensions (拡張型) 未確認飛行 C]<https://ufcpp.net/blog/2024/3/extensions/> を見るに、しばらく前から要望があったようです。
public static IEnumerable<TSource> operator +(IEnumerable<TSource> left, IEnumerable<TSource> right) => left.Concat(right);
}
}
Null 条件付き割り当て
namespace Dotnet10Feature;
/// <summary>
/// Null 条件付き割り当て
/// </summary>
/// <see href="https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14#null-conditional-assignment"/>
class NullConditionalAssignment
{
void NullAssign(Customer? customer)
{
// Null check can be simplified (IDE0031) が出るようになりました。
if (customer is not null)
{
customer.Order = GetCurrentOrder();
}
customer?.Order = GetCurrentOrder();
}
class Customer
{
public string? Order { get; set; } = null;
}
static string GetCurrentOrder()
{
return "CurrentOrder";
}
}
nameof は、バインドされていないジェネリック型をサポートします
namespace Dotnet10Feature;
/// <summary>
/// バインドされていないジェネリック型と nameof
/// </summary>
/// <see href="https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14#unbound-generic-types-and-nameof"/>
public static class UnboundGenericTypesAndNameof
{
public static void ShowExample()
{
// C# 14 以降では、 nameof する引数はバインドされていないジェネリック型にすることができます。
var nameofList = nameof(List<>);
// 以前のバージョンでは閉じたジェネリック型のみが使用可能でした。
// NOTE: Use unbound generic type (IDE0340) の警告が出ます。
var nameofListInt = nameof(List<int>);
}
}
単純なラムダ パラメーターの修飾子
field でサポートされるプロパティ
/// <summary>
/// field キーワード
/// </summary>
/// <see href="https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14#the-field-keyword"/>
class FieldFeature
{
#region
// fieldキーワードを使用した新しい形式です。
public string NewFormatProperty
{
get;
// fieldキーワードを使うと簡略化することができます。
// WARNING: `field`という名前のシンボルを含む型のコードがある場合には、ワークアラウンドが必要です。
// NOTE: null許容参照の警告が出ます。
set => field = value ?? throw new ArgumentNullException(nameof(value));
}
// 古い形式のプロパティ。VSCodeは、infoレベルでの警告となります。
// 自動的に新しい形式に変更することが可能です。
// NOTE: null許容参照の警告が出ます。
private string _msg; // この形式の場合には、バッキングフィールドの宣言が必要です。
public string OldFormatProperty
{
get => _msg;
set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}
#endregion
}
partial イベントとコンストラクター
namespace Dotnet10Feature;
public partial class MorePartialMembers
{
// partial classが非常に長くなる場合に、このようにメソッドのみの宣言を事前にしておくことが可能です。
// NOTE: staticは不可です。
partial void PartialMethod(string s);
// partial classで部分コンストラクターの宣言が可能になりました。
// https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/constructors#partial-constructors
public partial MorePartialMembers();
}
public partial class MorePartialMembers
{
partial void PartialMethod(string s) => Console.WriteLine($"Something happened: {s}");
public partial MorePartialMembers() // base()又はthis()の使用をする場合には、こちらに追加する必要があります。
{
// ここに実装宣言に追加することができます。
}
}
ユーザー定義複合代入演算子
namespace Dotnet10Feature;
/// <summary>
/// ユーザー定義複合割り当て
/// </summary>
/// <see href="https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/operators/operator-overloading"/>
class UserDefinedCompoundAssignment
{
class C1
{
public int Value;
public static C1 operator +(C1 operand) => operand;
public void operator +=(int x)
{
Value += x;
}
}
}
その他
-
Span<T>およびReadOnlySpan<T>のより暗黙的な変換
SDK と .NET 10 のツールの新機能
抜粋したものを記します。詳細は以下を参照してください。
- https://learn.microsoft.com/ja-jp/dotnet/core/compatibility/10.0#sdk-and-msbuild
- https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/sdk
- https://learn.microsoft.com/ja-jp/dotnet/core/compatibility/10.0#sdk-and-msbuild
slnx形式の対応
dotnet new slnの既定値が、SLNX ファイル形式になりました。
今まではプレビューでのみ利用可能でしたが、可読性が向上しました。
一回限りのツール実行
dotnet tool execはNode.jsにおける、npx相当の機能です。
.config/dotnet-tools.jsonがある場合には、それが考慮されます。
例えば、[CSharpier]https://www.nuget.org/packages/CSharpierを指定すると、以下のようになります。
$ dotnet tool exec CSharpier
ツール パッケージ csharpier@1.2.1 がソース https://api.nuget.org/v3/index.json からダウンロードされます。
続行しますか? [y/n] (y):
新しい dnx ツールの実行スクリプト
使い心地はdnx = dotnet dnx = dotnet tool execです。
dotnet tool exec より引用:
-
dotnet dnx-dnxスクリプト自体を簡単に実装する方法として使用されるdotnet tool execの非表示のエイリアス -
dnx- SDK からdotnet dnxを呼び出すシェル スクリプト。このスクリプトはインストーラーによって提供され、PATHで使用できます。dnx <toolname>を介して直接ツールを簡単に使用できます。
NOTE: 新しい dnx ツールの実行スクリプト の説明が分かりにくいので、dotnet tool exec を見る方が良いです。
ファイルベースのアプリの機能強化
C# 14 および .NET 10 以降では、 ファイル ベースのアプリを作成出来るようになりました。
Console.WriteLine("Hello, world!");
$ dotnet run hello.cs
Hello, world!
- https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/sdk#file-based-apps-enhancements
- https://learn.microsoft.com/ja-jp/dotnet/csharp/tour-of-csharp/overview#file-based-apps
NOTE: RC2時点では、[Announcing dotnet run app.cs – A simpler way o start with C# and .NET 10] https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/ にのみ記されていたものが、[SDK と .NET 10 のツールの新機能]https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/sdkの一項目として、明確に記載されました。
フレームワークによって提供されるパッケージ参照の排除
.NET 9では、推移的な依存関係に対してでしたが、さらに強化され、直接の依存関係に対しても不要なパッケージ参照の排除が可能になりました。
- https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/sdk#pruning-of-framework-provided-package-references
- https://learn.microsoft.com/ja-jp/nuget/consume-packages/package-references-in-project-files#prunepackagereference
より一貫性のあるコマンド順序
aliasが追加されました。
| 新しい名詞優先フォーム (New Noun-First Form) | エイリアス (Alias) |
|---|---|
dotnet package add |
dotnet add package |
dotnet package list |
dotnet list package |
dotnet package remove |
dotnet remove package |
dotnet reference add |
dotnet add reference |
dotnet reference list |
dotnet list reference |
dotnet reference remove |
dotnet remove reference |
ネイティブ シェルのタブ補完スクリプト
タブ補完が強化されました。タブ補完に用いるスクリプトを生成することができます。
dotnet completions script bash
タブ補完自体については、@nil2氏による、Bash用の補完スクリプトの作り方などを参照のこと。
その他
RuntimeIdentifiersを使う場合の使用感の向上
-
.NET ツールの機能強化
- プラットフォーム固有の .NET ツール
- プラットフォーム固有の .NET ツールで any RuntimeIdentifier を使用する
-
.NET Framework MSBuild で .NET MSBuild タスクを使用する
-
CLI コマンドは、対話式端末ではデフォルトで対話モードに設定されます
コンテナの機能の強化
- コンソール アプリでコンテナー イメージをネイティブに作成できる
- コンテナーのイメージ形式を明示的に制御する
Microsoft Testing Platformサポートの向上
- dotnet test における Microsoft Testing Platform のサポート
.NET ランタイム
以下の改善・機能強化がなされたとのことです。
詳細は[.NET 10 ランタイムの新機能] https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-10/runtimeを参照してください。
- JIT コンパイラの機能強化
- AVX10.2 のサポート
- スタックの割り当て
- NativeAOT 型の事前初期化機能の改善
- Arm64 書き込みバリアの機能強化
公式のコンテナイメージ
既定のイメージがDebianからUbuntuになりました。
mcr.microsoft.com/dotnet/sdk:10.0: Ubuntu 24.04 "Noble Numbat"
参考リンク
- [C# 14 / .NET 10 の新機能 (RC 1 時点)] https://speakerdeck.com/nenonaninu/net-10-noxin-ji-neng-rc-1-shi-dian
- RC 1時点の、何縫ねの。氏による解説です。
- [Microsoft、.NET 10をリリース —— Visual Studio 2026も一般提供開始] https://gihyo.jp/article/2025/11/dotnet-10
変更履歴
2025/11/14 コンテナイメージのセクションを追加
2025/11/14 .NET SDKの機能強化について更新
2025/11/06 拡張メンバーのコードが別のものになっていたため差し替えを実施
Discussion
「拡張メンバー」の項目の中身が「partial イベントとコンストラクター」の項目と同じものになっているようです!
ご指摘ありがとうございます。修正しました。