Search code examples
c#reflection

How to find public enum and public static methods defined in class through reflection


I am using reflection to inspect an assembly for types (classes) that implement a certain interface. When I find such a type, I then need to inspect the type to find methods and enums marked with a particular attribute.

I use the following to find methods:

foreach (MemberInfo member in types[index].FindMembers(MemberTypes.Method,
                                                   BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance,
                                                   new MemberFilter(WorkflowMethodFilter), ""))

WorkflowMethodFilter checks the MemberInfo for the presence of the custom attribute.

That works great for e.g.

[MyCustomAttr]
public void Method1() {...}

But static methods are not found in the call to FindMembers. That is, WorkflowMethodFilter is never called for static methods.

[MyCustomAttr]
public static void Method2() {...}

Is there a way to find static methods?

Any idea how I go about finding enums that are defined within the class?

public class Foo : IMyCustomInterface
{
     [MyCustomAttr]
     public enum MyEnum {...}
}

I have looked and looked, but haven't been able to find a way to find the enum through reflection.


Solution

  • Using Reflection you can easily retrieve properties and methods using GetMethods and GetProperties methods and filter on attribute implementation.

    For fields, use GetFields.

    For nested types, like your enum, you should use GetNestedTypes.

    Here is an example:

    using System;
    using System.Linq;
    using System.Reflection;
    
    Type classType = typeof(MyClass);
    
    Console.WriteLine($"Working with \"{classType.Name}\"");
    
    var methodsImplementingAttribute = classType.GetMethods()
        .Where(m => m.GetCustomAttributes(typeof(MyCustomAttribute), true).Length > 0) // Set inherit to true if it should check ancestors
        .ToList();
    
    foreach (MethodInfo method in methodsImplementingAttribute)
        Console.WriteLine($"Method with name \"{method.DeclaringType?.FullName ?? "NoDeclaringType"}.{method.Name}\" found implementing attribute");
    
    var propertiesImplementingAttribute = classType.GetProperties()
        .Where(p => p.GetCustomAttributes(typeof(MyCustomAttribute), false).Length > 0) //using GetCustomAttributes all defined attributes of Type
        .ToList();
    
    foreach (PropertyInfo property in propertiesImplementingAttribute)
        Console.WriteLine($"Property with name \"{property.DeclaringType?.FullName ?? "NoDeclaringType"}.{property.Name}\" found implementing attribute");
    
    var fieldsImplementingAttribute = classType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) //These binding flags are here because the fields are private
        .Where(f => f.GetCustomAttribute<MyCustomAttribute>(false) != null) //using GetCustomAttribute<T> returns a single attribute
        .ToList();
    
    foreach (FieldInfo field in fieldsImplementingAttribute)
        Console.WriteLine($"Field with name \"{field.DeclaringType?.FullName ?? "NoDeclaringType"}.{field.Name}\" found implementing attribute");
    
    var nestedTypesImplementingAttribute = classType.GetNestedTypes()
        .Where(e => e.GetCustomAttribute<MyCustomAttribute>(false) != null)
        .ToList();
    
    foreach (Type nestedType in nestedTypesImplementingAttribute)
        Console.WriteLine($"Nested type with name \"{nestedType.DeclaringType?.FullName ?? "NoDeclaringType"}.{nestedType.Name}\" found implementing attribute");
    
    public class MyClass : BaseClass
    {
        [MyCustom]
        int _attributeField = 0;
    
        int _attributelessField = 0;
    
        [MyCustom]
        public AttributeEnum AttributeProperty { get; set; }
    
        public int AttributeLessProperty { get; set; }
    
        [MyCustom]
        public void AttributeMethod() { }
    
        public override void AttributeMethodInherit() { }
    
        public void AttributelessMethod() { }
    
        [MyCustom]
        public enum AttributeEnum
        {
    
        }
        public enum AttributelessEnum
        {
    
        }
    }
    
    public class BaseClass
    {
        [MyCustom] //This is for the inherit example
        public virtual void AttributeMethodInherit() { }
    }
    
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Enum)]
    public class MyCustomAttribute : Attribute { }
    
    

    Output:

    Working with "MyClass"
    Method with name "MyClass.AttributeMethod" found implementing attribute
    Method with name "MyClass.AttributeMethodInherit" found implementing attribute
    Property with name "MyClass.AttributeProperty" found implementing attribute
    Field with name "MyClass._attributeField" found implementing attribute
    Nested type with name "MyClass.AttributeEnum" found implementing attribute
    

    Additionally, ensure your defined attributes ends with Attribute and not Attr, this is more standard and makes code predictable. This also allows you to omit the Attribute part when implementing the attribute.