C# コンパイラ エラー CS0609:IndexerName属性のオーバーライド制約について解説
エラー CS0609 は、C# のコードでオーバーライドされたインデクサーに IndexerName
属性を指定すると発生するコンパイラエラーです。
C# の仕様上、オーバーライドしたインデクサープロパティには属性の適用が禁止されているため、設定を削除することで解決できます。
なお、最新の Roslyn ではこの動作が変更され、エラーが表示されないこともあります。
エラーの原因と背景
C# におけるインデクサーの定義と仕様
C# では、インデクサーを用いてオブジェクトを配列のようにインデックスでアクセスできる機能が提供されています。
インデクサーはクラス内で this[]
として定義され、引数や戻り値の型が指定できます。
たとえば、あるクラス内で数値データを格納する場合、インデクサーを使って特定のインデックスにアクセスすることができます。
IndexerName 属性の役割と制約
IndexerName
属性は、インデクサーの名前を変更するために使用されます。
この属性は、デフォルトの名前 Item
を変更したい場合や、COM 相互運用のシナリオで特定の名前を使用する場合に役立ちます。
ただし、この属性は継承時のオーバーライドに使用することはできません。
すなわち、基底クラスのインデクサーをオーバーライドする際に IndexerName
属性を付与すると、コンパイラ エラー CS0609 が発生する制約があります。
CS0609 エラー発生の根本原因
エラー CS0609 は、オーバーライドされたインデクサーに対して IndexerName
属性を設定しようとした際に発生します。
C# 言語仕様では、オーバーライドによって継承されたインデクサーの名前は変更することができないため、このような属性の使用は認められていません。
エラーが発生した場合は、属性を削除するか、別の実装方法を検討する必要があります。
コード例の詳細解説
基底クラスにおけるインデクサー実装
以下のサンプルコードは、基底クラスでインデクサーを定義する例です。
このクラスでは、インデクサーを通じて数値データにアクセスできるようにしています。
using System;
// 基底クラス BaseClass 内でインデクサーを定義
public class BaseClass
{
// 仮想インデクサーの定義
public virtual int this[int index]
{
get
{
// サンプルとして引数の index に 10 を掛けた値を返す
return index * 10;
}
set
{
// 値設定処理 (ここでは特に処理は行わない)
}
}
}
public class Program
{
public static void Main(string[] args)
{
BaseClass baseObj = new BaseClass();
int result = baseObj[3];
// 期待値は 30
System.Console.WriteLine($"BaseClass のインデクサー呼び出し結果: {result}");
}
}
BaseClass のインデクサー呼び出し結果: 30
派生クラスでのオーバーライド時の属性使用例
以下のサンプルコードは、基底クラスのインデクサーを派生クラスでオーバーライドする際に、IndexerName
属性を付与している例です。
この場合、属性はオーバーライドされたインデクサーには適用できないためエラー CS0609 が発生します。
発生するエラーへの具体例
using System;
using System.Runtime.CompilerServices;
// 基底クラス idx で仮想インデクサーを定義
public class idx
{
public virtual int this[int iPropIndex]
{
get
{
// サンプルとして 0 を返す
return 0;
}
set
{
// 値設定処理 (ここでは処理はなし)
}
}
}
// 派生クラス MonthDays でオーバーライドし、IndexerName 属性を付与 (エラー発生)
public class MonthDays : idx
{
[IndexerName("MonthInfoIndexer")] // この行により CS0609 エラーが発生
public override int this[int iPropIndex]
{
get
{
return 0;
}
set
{
}
}
}
public class Program
{
public static void Main(string[] args)
{
MonthDays monthObj = new MonthDays();
int info = monthObj[5];
System.Console.WriteLine($"MonthDays のインデクサー呼び出し結果: {info}");
}
}
(コンパイルエラー CS0609 が発生するため、実行結果は出力されません。)
修正方法と検証手法
属性削除によるエラー解消方法
CS0609 エラーを回避するためには、派生クラスのオーバーライドされたインデクサーから IndexerName
属性を削除する必要があります。
以下は、エラーとなる属性を削除した正しいコード例です。
using System;
// 基底クラス idx で仮想インデクサーを定義
public class idx
{
public virtual int this[int iPropIndex]
{
get
{
// サンプルとして 0 を返す
return 0;
}
set
{
// 値設定処理 (ここでは処理なし)
}
}
}
// 派生クラス MonthDays でオーバーライド (IndexerName 属性は削除)
public class MonthDays : idx
{
public override int this[int iPropIndex]
{
get
{
return 100; // 任意のサンプル値
}
set
{
}
}
}
public class Program
{
public static void Main(string[] args)
{
MonthDays monthObj = new MonthDays();
int info = monthObj[2];
// 期待値は 100
System.Console.WriteLine($"修正後の MonthDays のインデクサー呼び出し結果: {info}");
}
}
修正後の MonthDays のインデクサー呼び出し結果: 100
コード修正後の動作確認ポイント
コードを修正した後は、以下の点を確認してください。
- コンパイルエラー CS0609 が発生しないこと
- 基底クラスと派生クラスともにインデクサーが正しく動作すること
Main
関数内でインデクサー呼び出し結果が期待通りであること
最新環境における動作の違い
Roslyn のバージョン差による挙動の違い
以前のコンパイラでは、オーバーライドされたインデクサーに IndexerName
属性を付与するとエラー CS0609 が発生します。
一方で、最新の Roslyn コンパイラでは、このエラーが抑制される場合がありますが、言語仕様上は依然として属性の使用が推奨されていません。
そのため、プロジェクトに適用されているコンパイラのバージョンに注意しつつ実装する必要があります。
対応方法と注意点
- コンパイラのバージョンが異なる環境では、同一のコードが異なる挙動を示す場合が存在するため、環境依存性を常に確認してください。
- 古いコンパイラを用いている場合は、エラー CS0609 が発生する可能性が高いため、オーバーライド時に
IndexerName
属性を使用しないよう修正してください。 - 最新のコンパイラを利用していても、将来的な互換性のために、属性の適用は避けるのが望ましいです。
- 開発チーム内でコード規約を整備し、属性使用に関する統一ルールを設けることで、開発環境の違いによる手戻りを防ぐことができます。
まとめ
本記事では、C#のインデクサーの定義や基本仕様、IndexerName属性の役割とその制約について解説しています。
派生クラスでオーバーライド時に属性を付与すると発生するCS0609エラーの原因や具体例、エラー解消のための属性削除による修正方法について説明しました。
さらに、Roslynコンパイラのバージョン違いによる挙動の差異と、その対応方法も取り上げています。