Cooooding!!

Unity(C#)を使ったゲーム開発関連Tipsなど

インデクサーのPropertyInfoを取得する【C#】

概要

Reflectionを使ってプロパティやフィールドにアクセスする実装をするときにインデクサー(添え字演算子)のPropertyInfo(MemberInfo)を取得する方法がわからなかったので調べてみました。

取得方法

大抵のケースでは以下のように"Item"という名前のプロパティを取得したらそれで済みます。

var property = typeof(TypeName).GetProperty("Item");

ただし、以下のようなケースでは単純に取得できない可能性があります。

  • IndexerNameAttributeが使われ"Item"以外の名前になっている可能性がある
  • 一つの型に複数のインデクサーが定義されている可能性がある
  • public以外で定義されている可能性がある
  • 基底クラスにも定義されている可能性がある

これらのケースにも対応するなら以下のような関数を用意して、複数見つかったらGetIndexParametersの型をチェックして目的のPropertyを探すのが良さそうです。

public static IList<PropertyInfo> GetIndexerPropertyInfoList(
    System.Type type,
    bool selfTypeOnly = false,
    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly
)
{
    var result = new List<PropertyInfo>();
    while (type != null)
    {
        foreach (var property in type.GetProperties(flags))
        {
            // 引数があるプロパティをインデクサーとみなす
            if (property.GetIndexParameters().Length > 0)
            {
                result.Add(property);
            }
        }
        // 基底クラスまでチェックしないならループを抜ける
        if(selfTypeOnly)
        {
            break;
        }
        type = type.BaseType;
    }
    return result;
}

余談

  • インデクサーの定義とは別に"Item"という名前のプロパティが既にあると名前が衝突してエラー(CS0102)になる。こういうケースでIndexerNameAttributeが使われる可能性がある
  • インデクサーのプロパティもその他のプロパティと同様にget_Item、set_Itemのようなメソッドが暗黙的に定義される
  • インデクサーにより暗黙的に定義されたメソッドと普通に定義されたメソッドの名前が衝突した場合もエラー(CS0082)になる
  • 複数のインデクサーがあるときに単純にGetPropertyすると「System.Reflection.AmbiguousMatchException : Ambiguous match found.」というエラーが発生する可能性がある

環境

  • VisualStudio 2019
  • Unity 2018.3.14f1 (.NET4.x)