C# 获取具有属性的静态方法并将其订阅到事件
如何通过反射获得所有应用了特定属性的静态方法,然后将这些方法订阅到事件 通过反射加载其方法的类:C# 获取具有属性的静态方法并将其订阅到事件,c#,events,reflection,C#,Events,Reflection,如何通过反射获得所有应用了特定属性的静态方法,然后将这些方法订阅到事件 通过反射加载其方法的类: public static class EventsAndStuff { [DoStuffEvent] public static void OnDoStuff(object sender, DoStuffEventArgs e) { // Do Stuff } } 这里有一个可能进行反射的地方,可以让事情变得清楚(在main()的开头) 当加载程序
public static class EventsAndStuff
{
[DoStuffEvent]
public static void OnDoStuff(object sender, DoStuffEventArgs e)
{
// Do Stuff
}
}
这里有一个可能进行反射的地方,可以让事情变得清楚(在main()
的开头)
当加载程序启动时,我将如何订阅事件dostuff()
,以便在调用dostuffent
时,调用应用了dostuffentattribute
的OnDoStuff和任何其他静态方法
我怀疑这与MethodInfo.CreateDelegate()
有关,但MSDN文档并不特别清楚
大多数类似的问题都涉及将非反射方法订阅到反射加载的事件。如何才能实现相反的操作?基本解决方案是迭代程序集中的类,您要搜索并测试这些类。静态类被编译器标记为密封和抽象的,因此您需要对此进行测试。然后,对于每个方法,检查它是否是静态的,以及属性是否存在。然后创建正确类型的委托并将其订阅到事件
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);
}
public类SubscriberAttribute:属性{}
静态类TestClass
{
[订阅]
静态void方法(对象发送方、事件args args)
{
WriteLine(“按预期调用的方法”);
}
静态无效未订阅(对象发送方、事件args args)
{
WriteLine(“调用了错误的方法!”);
}
}
类方法订户
{
[状态线程]
公共静态void Main()
{
var ms=new MethodSubscriber();
ms.SubscribeToEvent(typeof(MethodSubscriber).Assembly);
}
公共事件处理程序测试事件;
无效订阅事件(组件)
{
foreach(assembly.GetTypes()中的变量类型)
{
//静态类的测试
如果(type.isseald==false)继续;
如果(type.IsClass==false)继续;
//检查属性的每个方法。
foreach(类型为.GetRuntimeMethods()的var方法)
{
//确保该方法是静态的
如果(method.IsStatic==false)继续;
//测试属性是否存在
var attribute=method.GetCustomAttribute();
if(属性==null)
继续;
var del=(EventHandler)method.CreateDelegate(typeof(EventHandler));
TestEvent+=del;
}
}
TestEvent(null,EventArgs.Empty);
}
如果方法的签名与委托类型不匹配,则
CreateDelegate
方法将引发异常,因此您可能需要对这种情况进行某种处理。您可以通过反射方法参数并查看它们是否与事件预期的类型匹配来避免异常。我认为没有任何异常ng本机。所以你必须在构造函数中有一个类似的超类,你要反映所有方法并创建相关委托。因为现在你有一个实例签名,所以你不能在“程序加载”上执行此操作,除非你已经有了这些实例。哇!忘记了方法(和类)假设是静态的。如果它们是静态的,那么您基本上可以在程序集中的所有类中循环,查看哪些类应用了该属性,然后订阅事件。但是您仍然需要在该点上有事件源(例如,其他对象/Rx等).仅此而已。从语法上讲,如果知道并能够访问订阅的活动,这将如何实现?嗯,我被@Erik打败了,但我的解决方案基本上就是他所拥有的。谢谢!这正是我想要的。
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);
}