获取带属性的静态方法并将它们订阅到事件

时间:2015-03-01 02:31:29

标签: c# events reflection

如何通过反射获取具有某个属性的所有静态方法,然后将这些方法订阅到事件?

通过反射加载方法的类:

public static class EventsAndStuff
{
    [DoStuffEvent]
    public static void OnDoStuff(object sender, DoStuffEventArgs e)
    {
        // Do Stuff
    }
}

这是一个可以进行反思的地方,以便清楚地表明事情(在main()的开头)

public static class Program
{
    // event to subscribe to
    public static event DoStuffEventHandler DoStuff;

    public static void Main(string[] args)
    {
        // reflection here
    }
}

当加载程序启动时,我如何订阅OnDoStuff()到事件DoStuffEvent,这样当调用DoStuffEvent时,它会调用OnDoStuff和任何其他静态方法{ {1}}已申请?

我怀疑这与DoStuffEventAttribute有关,但MSDN文档并不是特别清楚。

大多数类似问题涉及为反射加载事件订阅非反射方法。怎么可能反过来?

1 个答案:

答案 0 :(得分:2)

基本解决方案是遍历要搜索的程序集(-ies)中的类并测试类。静态类由编译器标记为密封和抽象,因此您需要对其进行测试。然后,对于每个方法,检查它是否是静态的以及属性是否存在。然后创建正确类型的委托并订阅该事件。

public class SubscriberAttribute : Attribute { }

static class TestClass
{
    [SubscriberAttribute]
    static void Method(object sender, EventArgs args)
    {
        Console.WriteLine("Method called as expected.");
    }

    static void Nonsubscribed(object sender, EventArgs args)
    {
        Console.WriteLine("Wrong method called!");
    }
}

class MethodSubscriber
{
    [STAThread]
    public static void Main()
    {
        var ms = new MethodSubscriber();

        ms.SubscribeToEvent(typeof(MethodSubscriber).Assembly);
    }

    public event EventHandler TestEvent;

    void SubscribeToEvent(Assembly assembly)
    {
        foreach (var type in assembly.GetTypes())
        {
            // Test for a static class
            if (type.IsSealed == false) continue;
            if (type.IsClass == false) continue;

            // Check each method for the attribute.
            foreach (var method in type.GetRuntimeMethods())
            {
                // Make sure the method is static
                if (method.IsStatic == false) continue;

                // Test for presence of the attribute
                var attribute = method.GetCustomAttribute<SubscriberAttribute>();

                if (attribute == null)
                    continue;

                var del = (EventHandler)method.CreateDelegate(typeof(EventHandler));

                TestEvent += del;
            }
        }

        TestEvent(null, EventArgs.Empty);
    }

如果方法的签名与委托类型不匹配,CreateDelegate方法将抛出异常,因此您可能希望对该情况进行某种处理。您可以通过反映方法参数并查看它们是否与事件预期的类型匹配来避免异常。