如何将事件赋值给另一事件?EventAssign实例属性与事件复制咨询
嘿,这个问题我之前碰到过好多次——.NET里的事件默认确实没法像普通属性那样直接复制,因为事件本质是对委托的封装,对外只开放订阅/取消订阅的接口,不让直接碰背后的委托实例。不过有几种可行的办法,你可以根据自己的场景选:
方法1:利用反射获取事件背后的委托字段
事件在编译后通常会生成对应的私有委托字段(比如默认命名是_changed,如果是C#自动实现的事件,字段名可能是<Changed>k__BackingField)。你可以通过反射找到这个字段,把源实例的委托值直接赋值给目标实例的对应字段。
示例代码:
using System.Reflection; public static void CopyEvent(EventAssign source, EventAssign target) { // 注意字段名可能因编译设置、.NET版本不同而变化 FieldInfo eventField = typeof(EventAssign).GetField( "_changed", BindingFlags.Instance | BindingFlags.NonPublic); if (eventField != null) { Delegate sourceDelegate = (Delegate)eventField.GetValue(source); eventField.SetValue(target, sourceDelegate); } }
⚠️ 注意:这种方法依赖编译器生成的字段名,兼容性不是100%,而且反射有一定性能开销,还需要足够权限访问私有字段,属于“应急方案”。
方法2:在
EventAssign类内部提供事件复制方法 这是最稳妥、可控的方案——既然你能控制EventAssign的代码,不如直接在类里加一个专门处理事件订阅复制的方法,完全不用依赖反射。
修改你的EventAssign类:
public class EventAssign { // 把自动实现的事件改成手动实现,暴露内部委托字段 private EventHandler _changed; public event EventHandler Changed { add => _changed += value; remove => _changed -= value; } // 你的其他属性... // 新增复制事件订阅的方法 public void CopyEventSubscriptionsFrom(EventAssign source) { // 可选:先清空目标实例的现有订阅 _changed = null; // 直接复制源实例的委托 _changed = source._changed; } }
使用起来非常简单:
EventAssign source = new EventAssign(); // 给source的Changed事件订阅处理方法... EventAssign target = new EventAssign(); // 先复制所有属性(这里假设你已经完成属性复制) // 然后复制事件订阅 target.CopyEventSubscriptionsFrom(source);
方法3:遍历委托调用列表逐个订阅
如果没法修改原类,也不想用反射,还有个“笨办法”:获取源事件委托的调用列表,逐个订阅到目标实例的事件上。不过前提是你能拿到源实例的委托(可以结合方法1的反射方式)。
示例代码:
public static void CopyEventHandlers(EventAssign source, EventAssign target) { FieldInfo eventField = typeof(EventAssign).GetField("_changed", BindingFlags.Instance | BindingFlags.NonPublic); if (eventField == null) return; Delegate sourceDelegate = (Delegate)eventField.GetValue(source); if (sourceDelegate == null) return; // 遍历每个事件处理方法,订阅到目标实例 foreach (Delegate handler in sourceDelegate.GetInvocationList()) { target.Changed += (EventHandler)handler; } }
这种方法的好处是可以选择追加订阅(而不是直接覆盖),适合需要保留目标实例原有订阅的场景。
总的来说,最推荐方法2,安全可控;方法1适合没法修改原类的应急场景;方法3是灵活的备选方案。
内容的提问来源于stack exchange,提问作者Amal
相关产品推荐
相关产品推荐

