Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get declared and inherited members from TypeInfo

In the new Reflection API, the TypeInfo.Declared* properties are the right way to access the members (fields, properties, methods, etc) declared on a type. However, these properties do not include members inherited from a base class.

The old TypeInfo.GetRuntime*() methods return both declared and inherited members, but are not available on all platforms, including .NET Core.

How do I get a list of declared and inherited members with the new API?

like image 697
Nate Barbettini Avatar asked Feb 12 '16 19:02

Nate Barbettini


1 Answers

I wrote a set of small extension methods that provide this functionality:

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();
        }
    }
}

This should be super easy to use. Calling typeInfo.GetAllProperties(), for example, will return all of the DeclaredProperties of the current type and any base types, all the way up the inheritance tree.

I'm not imposing any ordering here, so if you need to enumerate members in a specific order, you may have to tweak the logic.


Some simple tests to demonstrate:

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; }
}

These extension methods are compatible with both desktop .NET 4.5+ and .NET Core.

like image 64
Nate Barbettini Avatar answered Oct 20 '22 19:10

Nate Barbettini