Search code examples
c#reflectionbindingflags

See if MemberInfo matches BindingFlags using C#


I need to see if a MemberInfo matches a particular BindingFlags. The closest method to this is Type#GetMember(string, BindingFlags).

I cannot find any method to do this.

I want to do something like this:

private List<MemberInfo> _members;

public IEnumerable<MemberInfo> GetMembers(BindingFlags flags)
{
    foreach(var member in _members)
    {
        if(member.MatchesFlags(flags))
        {
             yield return member;
        }
    }
}

Solution

  • Actual types of MemberInfo obtained with reflection (e.g. via calling MemberInfo[] GetMembers() on Type) are:

    • System.Reflection.RuntimeMethodInfo
    • System.Reflection.RuntimeConstructorInfo
    • System.Reflection.RuntimePropertyInfo
    • System.Reflection.RtFieldInfo

    All of them independently have property BindingFlags of type BindingFlags. But the property is NonPublic. And the types are internal sealed, that makes them inaccessible in normal code. Here reflection comes to rescue. To get BindingFlags of a MemberInfo one can use such an extension:

    public static class MemberInfoExtension
    {
        private static readonly Dictionary<MemberInfo, BindingFlags> cache =
            new Dictionary<MemberInfo, BindingFlags>();
        private static readonly BindingFlags flags =
            BindingFlags.Instance | BindingFlags.NonPublic;
    
        public static BindingFlags GetFlags(this MemberInfo memberInfo)
        {
            if (cache.TryGetValue(memberInfo, out var bindingFlags))
                return bindingFlags;
    
            return cache[memberInfo] =
                (BindingFlags)memberInfo.GetType()
                                        .GetProperty("BindingFlags", flags)
                                        .GetValue(memberInfo);
        }
    }
    

    To find matches with BindingFlags the following helper methods can be used:

    public static class BindingFlagsExtension
    {
        public static bool Contains(this BindingFlags flags, BindingFlags bindingFlags) =>
            (flags & bindingFlags) == bindingFlags;
    
        public static bool MatchesExactly(this BindingFlags flags, BindingFlags bindingFlags) =>
            flags == bindingFlags;
    
        public static bool MatchesPartly(this BindingFlags flags, BindingFlags bindingFlags) =>
            (flags & bindingFlags) != 0;
    }
    

    To test the solution one can use a class like this:

    private class DemoClass
    {
        private int PrivateInstanceField;
        public string PublicInstanceField;
        private bool PrivateInstanceProperty { get; }
        public object PublicInstanceProperty { get; }
        private void PrivateInstanceMethod() { }
        public void PublicInstanceMethod() { }
        private static int PrivateStaticField;
        public static string PublicStaticField;
        private static bool PrivateStaticProperty { get; }
        public static object PublicStaticProperty { get; }
        private static void PrivateStaticMethod() { }
        public static void PublicStaticMethod() { }
    }
    

    Then running:

    static void Main(string[] args)
    {
        var type = typeof(DemoClass);
        var members = type.GetMembers();
        var flags = BindingFlags.Public | BindingFlags.Instance;
    
        Console.WriteLine($"{type.Name} members with flags containing: {flags}\n");
        foreach (var m in members.Where(m => m.GetFlags().Contains(flags)))
            Print(m);
    
        Console.WriteLine($"\n{type.Name} members with flags matching exactly: {flags}\n");
        foreach (var m in members.Where(m => m.GetFlags().MatchesExactly(flags)))
            Print(m);
    
        Console.WriteLine($"\n{type.Name} members with flags matching partly: {flags}\n");
        foreach (var m in members.Where(m => m.GetFlags().MatchesPartly(flags)))
            Print(m);
    }
    
    private static void Print(MemberInfo memberInfo) =>
        Console.WriteLine($"\t{memberInfo.GetType().Name} {memberInfo} - {memberInfo.GetFlags()}");
    

    gives:

    DemoClass members with flags containing: Instance, Public
    
            RuntimeMethodInfo System.Object get_PublicInstanceProperty() - Instance, Public
            RuntimeMethodInfo Void PublicInstanceMethod() - Instance, Public
            RuntimeMethodInfo Boolean Equals(System.Object) - DeclaredOnly, Instance, Public
            RuntimeMethodInfo Int32 GetHashCode() - DeclaredOnly, Instance, Public
            RuntimeMethodInfo System.Type GetType() - DeclaredOnly, Instance, Public
            RuntimeMethodInfo System.String ToString() - DeclaredOnly, Instance, Public
            RuntimeConstructorInfo Void .ctor() - Instance, Public
            RuntimePropertyInfo System.Object PublicInstanceProperty - Instance, Public
            RtFieldInfo System.String PublicInstanceField - Instance, Public
    
    DemoClass members with flags matching exactly: Instance, Public
    
            RuntimeMethodInfo System.Object get_PublicInstanceProperty() - Instance, Public
            RuntimeMethodInfo Void PublicInstanceMethod() - Instance, Public
            RuntimeConstructorInfo Void .ctor() - Instance, Public
            RuntimePropertyInfo System.Object PublicInstanceProperty - Instance, Public
            RtFieldInfo System.String PublicInstanceField - Instance, Public
    
    DemoClass members with flags matching partly: Instance, Public
    
            RuntimeMethodInfo System.Object get_PublicInstanceProperty() - Instance, Public
            RuntimeMethodInfo Void PublicInstanceMethod() - Instance, Public
            RuntimeMethodInfo System.Object get_PublicStaticProperty() - Static, Public
            RuntimeMethodInfo Void PublicStaticMethod() - Static, Public
            RuntimeMethodInfo Boolean Equals(System.Object) - DeclaredOnly, Instance, Public
            RuntimeMethodInfo Int32 GetHashCode() - DeclaredOnly, Instance, Public
            RuntimeMethodInfo System.Type GetType() - DeclaredOnly, Instance, Public
            RuntimeMethodInfo System.String ToString() - DeclaredOnly, Instance, Public
            RuntimeConstructorInfo Void .ctor() - Instance, Public
            RuntimePropertyInfo System.Object PublicInstanceProperty - Instance, Public
            RuntimePropertyInfo System.Object PublicStaticProperty - Static, Public
            RtFieldInfo System.String PublicInstanceField - Instance, Public
            RtFieldInfo System.String PublicStaticField - Static, Public