如何通过反射订阅外部类的内部静态Action事件?
订阅/移除内部静态Action事件的方案
因为目标事件是internal访问修饰符的静态事件,且无法修改定义它的类,只能通过反射绕过访问限制完成委托的订阅与移除。以下是具体实现步骤和代码示例:
核心思路
自动实现的event在编译后会生成对应私有静态字段(字段名格式为<事件名>k__BackingField),我们可以通过反射获取该字段,直接操作字段值来添加或移除委托。
添加委托的代码示例
using System; using System.Reflection; // 假设外部类名为ExternalSingletonClass Type targetType = typeof(ExternalSingletonClass); // 获取事件对应的后台字段 FieldInfo eventField = targetType.GetField("<OnSingletonReady>k__BackingField", BindingFlags.Static | BindingFlags.NonPublic); if (eventField != null) { // 定义要订阅的委托逻辑 Action myHandler = () => { Console.WriteLine("Singleton ready event triggered"); }; // 获取当前事件的委托实例 Action currentDelegate = (Action)eventField.GetValue(null); // 合并新委托与现有委托 Action newDelegate = (Action)Delegate.Combine(currentDelegate, myHandler); // 将合并后的委托赋值回字段 eventField.SetValue(null, newDelegate); }
移除委托的代码示例
using System; using System.Reflection; Type targetType = typeof(ExternalSingletonClass); FieldInfo eventField = targetType.GetField("<OnSingletonReady>k__BackingField", BindingFlags.Static | BindingFlags.NonPublic); if (eventField != null) { // 注意:必须引用之前订阅时的同一个委托实例 Action myHandler = // 此处关联订阅时保存的委托对象 Action currentDelegate = (Action)eventField.GetValue(null); // 从现有委托中移除目标委托 Action newDelegate = (Action)Delegate.Remove(currentDelegate, myHandler); eventField.SetValue(null, newDelegate); }
注意事项
- 字段名兼容性:自动实现事件的后台字段名格式
<事件名>k__BackingField是C#编译器的标准生成规则,但如果目标事件是手动实现的(而非自动属性式定义),则需要找到对应的实际字段名。 - 委托实例一致性:移除委托时必须使用和订阅时完全相同的委托实例,否则
Delegate.Remove无法生效,建议将订阅的委托对象保存为类成员变量方便后续操作。 - 反射权限:确保程序运行时有足够权限访问私有成员,普通应用场景下无需额外配置,但沙箱或严格权限控制场景可能受限。
内容的提问来源于stack exchange,提问作者CodeSmile
相关产品推荐
相关产品推荐

