Start Debugging

C# 15 の拡張インデクサーが .NET 11 Preview 6 で拡張メンバーを完成させる

拡張インデクサーが .NET 11 Preview 6 に登場し、自分が管理していない型に this[...] アクセスを追加できるようになりました。C# 14 のメソッドとプロパティから始まった拡張メンバーの物語を完成させます。

.NET 11 Preview 6 は 2026-07-14 にリリースされ、リリースノートの C# セクションには拡張メンバーをついに完成したものに感じさせる要素が隠れています。それが拡張インデクサーです。拡張メソッドは C# 3.0 から存在し、拡張プロパティは C# 14 の拡張ブロックとともに登場しました。そして今では、自分が管理していない型に this[...] アクセスを追加できます。

これまで欠けていたもの

これまで明白な回避策は、普通の拡張メソッドでした。Index を理解するインデクサーを持たない IReadOnlyList<T> に対して末尾からのインデックスのセマンティクスが欲しければ、次のように書いていました。

public static class ReadOnlyListExtensions
{
    public static T At<T>(this IReadOnlyList<T> list, Index index)
        => list[index.GetOffset(list.Count)];
}

// call site
IReadOnlyList<string> log = ["start", "work", "done"];
Console.WriteLine(log.At(^1));   // done
Console.WriteLine(log.At(^2));   // work

これは動作しますが、呼び出し側は他のあらゆるリスト風の型が提供する log[^1] 構文ではなく log.At(^1) と読めてしまいます。角かっこ記法を失い、リストパターンでもそれを失います。

拡張インデクサー版

C# 15 では、インスタンスインデクサーを宣言するのとまったく同じように、extension ブロックの中でインデクサーを宣言できます。

public static class ReadOnlyListExtensions
{
    extension<T>(IReadOnlyList<T> list)
    {
        public T this[Index index] => list[index.GetOffset(list.Count)];
    }
}

// call site
IReadOnlyList<string> log = ["start", "work", "done"];
Console.WriteLine(log[^1]);   // done
Console.WriteLine(log[^2]);   // work

extension<T>(IReadOnlyList<T> list) というヘッダーで捕捉されたレシーバーは本体の中でスコープに入っているため、インデクサーは直接 list に転送します。呼び出し側は本物のインデクサー構文を使うようになり、コンパイラーがそれをインデクサーとして扱うため、組み込みのものと同じようにリストパターンや範囲式に参加します。

拡張インデクサーは、パラメーターが 1 つで読み取り専用の形に限られません。複数のパラメーターと get および set アクセサーをサポートするので、2 次元のルックアップをフラットなバッキングストアに射影したり、メソッドベースのアクセスしか提供しない型の上に書き込み可能なビューを公開したりできます。

有効化する方法

これはまだプレビューの言語機能なので、既定の言語バージョンでは有効になりません。次を .csproj に追加してください。

<LangVersion>preview</LangVersion>

拡張インデクサーは、古典的な 3 種類のメンバーのうち拡張ブロックに到達する最後のものです。つまりメンタルモデルはこれで統一されます。メソッド、プロパティ、インデクサーはすべて extension(...) の中で同じように宣言します。欠けているインデクサーを補うためにラッパー型やぎこちない .At() ヘルパーに頼ってきたなら、Preview 6 はそれらを削除できるリリースです。詳しい解説は Preview 6 リリースノートの C# セクションを参照してください。

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る