2016-02-12 21 views
5

new Reflection APIでは、タイプに宣言されたメンバー(フィールド、プロパティ、メソッドなど)にアクセスするための適切な方法がTypeInfo.Declared*のプロパティです。ただし、これらのプロパティには基本クラスから継承されたメンバーは含まれません。TypeInfoから宣言メンバーおよび継承メンバーを取得する方法

古いTypeInfo.GetRuntime*()メソッドは、宣言メンバーと継承メンバーの両方を返しますが、.NETコアを含むすべてのプラットフォームでは使用できません。

新しいAPIを使用して継承されたメンバーが宣言されたリストを取得するにはどうすればよいですか?

答えて

16

私はこの機能を提供する小型の拡張メソッドのセットを書いた:

public static class TypeInfoAllMemberExtensions 
{ 
    public static IEnumerable<ConstructorInfo> GetAllConstructors(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredConstructors); 

    public static IEnumerable<EventInfo> GetAllEvents(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredEvents); 

    public static IEnumerable<FieldInfo> GetAllFields(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredFields); 

    public static IEnumerable<MemberInfo> GetAllMembers(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredMembers); 

    public static IEnumerable<MethodInfo> GetAllMethods(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredMethods); 

    public static IEnumerable<TypeInfo> GetAllNestedTypes(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredNestedTypes); 

    public static IEnumerable<PropertyInfo> GetAllProperties(this TypeInfo typeInfo) 
     => GetAll(typeInfo, ti => ti.DeclaredProperties); 

    private static IEnumerable<T> GetAll<T>(TypeInfo typeInfo, Func<TypeInfo, IEnumerable<T>> accessor) 
    { 
     while (typeInfo != null) 
     { 
      foreach (var t in accessor(typeInfo)) 
      { 
       yield return t; 
      } 

      typeInfo = typeInfo.BaseType?.GetTypeInfo(); 
     } 
    } 
} 

これは、使用する超簡単でなければなりません。たとえば、typeInfo.GetAllProperties()を呼び出すと、現在のタイプとすべての基本タイプのDeclaredPropertiesがすべて継承ツリーまで返されます。

私はここで注文しているわけではないので、メンバーを特定の順序で列挙する必要がある場合は、ロジックを調整する必要があります。


実証するためのいくつかの簡単なテスト:

public class Test 
{ 
    [Fact] 
    public void Get_all_fields() 
    { 
     var fields = typeof(TestDerived).GetTypeInfo().GetAllFields(); 

     Assert.True(fields.Any(f => f.Name == "FooField")); 
     Assert.True(fields.Any(f => f.Name == "BarField")); 
    } 

    [Fact] 
    public void Get_all_properties() 
    { 
     var properties = typeof(TestDerived).GetTypeInfo().GetAllProperties(); 

     Assert.True(properties.Any(p => p.Name == "FooProp")); 
     Assert.True(properties.Any(p => p.Name == "BarProp")); 
    } 
} 

public class TestBase 
{ 
    public string FooField; 

    public int FooProp { get; set; } 
} 

public class TestDerived : TestBase 
{ 
    public string BarField; 

    public int BarProp { get; set; } 
} 

これらの拡張メソッドは、デスクトップ.N​​ET 4.5+および.NETのコアの両方と互換性があります。

関連する問題