如何通过反射清除 class 中的所有静态事件处理程序?
How to clear all static event handlers in a class via reflection?
我有带有大量静态事件回调的 STATIC class。我不想硬编码重置方法,而是想使用反射来自动清除所有事件订阅。
public static void NotifyA(int p1) { notifyA?.Invoke(p1); }
public static event Action<int> notifyA;
public static void NotifyB(float p1) { notifyB?.Invoke(p1); }
public static event Action<float> notifyB;
// and so on...
我卡在这个阶段不知道如何真正清除事件。
public static void ResetEvents()
{
var type = typeof(ClientEvents);
var events = type.GetEvents(BindingFlags.Static | BindingFlags.Public);
foreach (var current in events )
{
// current.RemoveEventHandler(???);
}
}
通常,在 .NET 中“删除所有订阅者”是没有意义的。事件甚至不需要记住他们的订阅者是谁!一个事件实际上只是一对方法,称为 add
和 remove
,它们将某种类型的委托作为参数,您可以在这些方法中做任何您想做的事情,例如
public static event Action<int> MySillyEvent {
add {
Console.WriteLine($"{value.Method.Name} is being added!");
}
remove {
Console.WriteLine($"{value.Method.Name} is being removed!");
}
}
现在告诉我,“从 MySillyEvent
中删除所有订阅者”是什么意思?
如果您将范围限制在 field-like events,这是由委托字段支持的事件,那么这是一个更容易处理的问题。您只需将支持事件的委托字段设置为 null。您的 notifyA
和 notifyB
事件是类似字段的事件。
但是,委托字段的名称是依赖于实现的,EventInfo
不知道它是否是类字段。
如果您的 class 没有任何显式声明的静态委托字段,您可以在 class 中找到所有非 public、委托类型的静态字段:
var fields = typeof(ClientEvents).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
.Where(x => x.FieldType.BaseType.IsSubclassOf(typeof(Delegate)));
foreach (var field in fields) {
field.SetValue(null, null);
}
否则,您需要依赖一些实现细节,例如 。我们假设字段名称与事件名称相同。这至少适用于我正在使用的编译器。
var type = typeof(ClientEvents);
var fields = type.GetEvents(BindingFlags.Static | BindingFlags.Public)
.Select(e => type.GetField(e.Name, BindingFlags.Static | BindingFlags.NonPublic));
foreach (var field in fields) {
field.SetValue(null, null);
}
如果ResetEvents
方法在同一个静态class中,那么你甚至不需要反射:
//public static event Action<int> notifyA;
private static Action<int> notifyAHandler;
public static event Action<int> NotifyA
{
add => notifyAHandler += value;
remove => notifyAHandler -= value;
}
public static void ResetEvents()
{
notifyAHandler = null;
// ...
}
如果你真的想使用反射,那么迭代委托类型的静态字段,并将它们设置为 null。
备注: 按照惯例,所有带有数据的事件都应该使用 EventHandler<TEventArgs>
委托,即使 sender
是 null
对于静态事件.
我有带有大量静态事件回调的 STATIC class。我不想硬编码重置方法,而是想使用反射来自动清除所有事件订阅。
public static void NotifyA(int p1) { notifyA?.Invoke(p1); }
public static event Action<int> notifyA;
public static void NotifyB(float p1) { notifyB?.Invoke(p1); }
public static event Action<float> notifyB;
// and so on...
我卡在这个阶段不知道如何真正清除事件。
public static void ResetEvents()
{
var type = typeof(ClientEvents);
var events = type.GetEvents(BindingFlags.Static | BindingFlags.Public);
foreach (var current in events )
{
// current.RemoveEventHandler(???);
}
}
通常,在 .NET 中“删除所有订阅者”是没有意义的。事件甚至不需要记住他们的订阅者是谁!一个事件实际上只是一对方法,称为 add
和 remove
,它们将某种类型的委托作为参数,您可以在这些方法中做任何您想做的事情,例如
public static event Action<int> MySillyEvent {
add {
Console.WriteLine($"{value.Method.Name} is being added!");
}
remove {
Console.WriteLine($"{value.Method.Name} is being removed!");
}
}
现在告诉我,“从 MySillyEvent
中删除所有订阅者”是什么意思?
如果您将范围限制在 field-like events,这是由委托字段支持的事件,那么这是一个更容易处理的问题。您只需将支持事件的委托字段设置为 null。您的 notifyA
和 notifyB
事件是类似字段的事件。
但是,委托字段的名称是依赖于实现的,EventInfo
不知道它是否是类字段。
如果您的 class 没有任何显式声明的静态委托字段,您可以在 class 中找到所有非 public、委托类型的静态字段:
var fields = typeof(ClientEvents).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
.Where(x => x.FieldType.BaseType.IsSubclassOf(typeof(Delegate)));
foreach (var field in fields) {
field.SetValue(null, null);
}
否则,您需要依赖一些实现细节,例如
var type = typeof(ClientEvents);
var fields = type.GetEvents(BindingFlags.Static | BindingFlags.Public)
.Select(e => type.GetField(e.Name, BindingFlags.Static | BindingFlags.NonPublic));
foreach (var field in fields) {
field.SetValue(null, null);
}
如果ResetEvents
方法在同一个静态class中,那么你甚至不需要反射:
//public static event Action<int> notifyA;
private static Action<int> notifyAHandler;
public static event Action<int> NotifyA
{
add => notifyAHandler += value;
remove => notifyAHandler -= value;
}
public static void ResetEvents()
{
notifyAHandler = null;
// ...
}
如果你真的想使用反射,那么迭代委托类型的静态字段,并将它们设置为 null。
备注: 按照惯例,所有带有数据的事件都应该使用 EventHandler<TEventArgs>
委托,即使 sender
是 null
对于静态事件.