C# 14 を使いたい! そう思っていますね? わかります。私もです。
.NET 10 ももうリリースになります。となれば当然に皆さんお待ちかねの C# 14 を皆が使い始めます。私も使います。
■ 前回までの C# 14
C# 14 の新機能ですが、前回の記事で機能リスト的には Preview 版の時に追いかけていた内容とほぼ同じだとわかりました。
1 項目差がありましたがこれは後日見ていきたいと思います。
■ 以前の確認コード
Preview 版の時に追っていたということは、機能確認コードがすでにあるということです。Preview 版の時のコードはまだ動くのか、見てみましょう。
確認コードはこちらです。
github.com
■ ビルドしてみる
当時のコードをなにもせずに、ビルドしてみます。
なんと! エラーが 2 件出ました。逆にエラーが 2 件しか出ませんでした。しかも 2 件は同じ内容で、実質 1 件だけのエラーです。

'Combine': cannot declare instance members in an extension block with an unnamed receiver parameter 'Empty_2': cannot declare instance members in an extension block with an unnamed receiver parameter
エラーが出ているのは 拡張メンバー定義 です。確認コード全体をまずは掲載。
概ね、4 つの確認をしていて、
- 通常の拡張メンバーの定義
- 静的メンバーも追加できることの確認
- ジェネリクス型の確認
- ジェネリクス型の静的メンバーの確認 です。確認コード全体をまずは掲載。
// 拡張メンバー定義 // 一つのクラスに複数定義可能 public static class SampleExtension { // string に対する拡張メンバー // 引数に this は必要ない extension(string s) { // メンバーのシグニチャに this の引数は不要 // 一つの extension ブロックの中に複数定義可能 public bool IsEmpty => (s?.Length ?? 0) == 0; public bool IsEmpty_2 => (s?.Length ?? 0) == 0; // メソッドも定義可能 public bool Empty() => (s?.Length ?? 0) == 0; } // 静的メンバーも定義可能 extension(string) { // 静的メソッド public string Combine(string first, string second) => first + second; // 静的プロパティ public string Empty_2 => string.Empty; } // ジェネリクス型に対する拡張メンバー extension<TSource>(IEnumerable<TSource> source) { public bool IsEmpty => !source.Any(); } // ジェネリクス型に対する拡張メンバー extension<TSource>(IEnumerable<TSource>) { public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second) => Enumerable.Empty<TSource>(); public static IEnumerable<TSource> Identity => Enumerable.Empty<TSource>(); } }
■ どこがエラーになっているか
静的メンバーの追加です。
既存コード
// 静的メンバーも定義可能 extension(string) { // 静的メソッド public string Combine(string first, string second) => first + second; // 静的プロパティ public string Empty_2 => string.Empty; }
今回エラーを改修したコード
// 静的メンバーも定義可能 extension(string) { // 静的メソッド public static string Combine(string first, string second) => first + second; // 静的プロパティ public static string Empty_2 => string.Empty; }
■ 何が違うか
static キーワードが付いています。これ、ジェネリクスの時は以前からついていましたし、そもそも静的メンバーですし、これでいいのだって感じですね。
もしかしたら、私が間違えていてもともと static 付きが使用だったのかもと思うほどです。
■ 改修コード
改修版のコードは、既存のコードを変えずに別プロジェクトで書いています。
■ 拡張メンバーは静的メンバーなのか
拡張メンバーはもともと、拡張メンバーを定義しているクラスの静的メンバーでした。つまり、第一引数に拡張対象のインスタンスを自分で渡すことで普通に静的メンバーとして使うことも可能でした。
例えばこんな感じです。
public static class SampleOldExtension { // 第一引数に this を付けることで拡張メソッドとして定義 public static bool IsEmpty(this int i) => i == 0; }
Console.WriteLine(SampleOldExtension.IsEmpty(0)); Console.WriteLine(SampleOldExtension.IsEmpty(1));
■ 通常の拡張メンバーを拡張対象のメソッドとして
extension(string s) { // メンバーのシグニチャに this の引数は不要 // 一つの extension ブロックの中に複数定義可能 public bool IsEmpty => (s?.Length ?? 0) == 0; public bool IsEmpty_2 => (s?.Length ?? 0) == 0; // メソッドも定義可能 public bool Empty() => (s?.Length ?? 0) == 0; }
インテリセンスで静的メンバーとして出てきませんね。まあそうといえばそうでしょう。

■ 静的拡張メンバー
インテリセンスで静的メンバーとして出てきます。
// 静的メンバーも定義可能 extension(string) { // 静的メソッド public static string Combine(string first, string second) => first + second; // 静的プロパティ public static string Empty_2 => string.Empty; }

■ 拡張メンバーの定義クラスの静的メンバーとして
インテリセンスで出てきますね。まあそうといえばそうでしょう。しかしプロパティはだけ注目です。
名前の先頭に get_ が付いています。これは注目ですね。自分で get_ を付けたメソッドを作っていた場合の名前競合でどうなるのか。後日見てい観たいと思います。

■ 次回
次回は、既存の確認コードの確認 その 2。何もしなくてもビルドできるか、ではなく変えるべきところを変えてビルドできるか、を見ていきます。