【发布时间】:2010-10-09 00:41:48
【问题描述】:
我需要将一个事件的订阅者复制到另一个事件。我可以获取事件的订阅者(例如 MyEvent[0] 返回委托)吗?
如果这不可能,我会使用 add 访问器将代表添加到列表中。这会是最好的解决方案吗?
【问题讨论】:
我需要将一个事件的订阅者复制到另一个事件。我可以获取事件的订阅者(例如 MyEvent[0] 返回委托)吗?
如果这不可能,我会使用 add 访问器将代表添加到列表中。这会是最好的解决方案吗?
【问题讨论】:
C# 事件/委托是多播的,因此委托本身是一个列表。在班级内,要获取个别呼叫者,您可以使用:
if (field != null)
{
// or the event-name for field-like events
// or your own event-type in place of EventHandler
foreach(EventHandler subscriber in field.GetInvocationList())
{
// etc
}
}
但是,要一次全部赋值,只需使用 += 或直接赋值:
SomeType other = ...
other.SomeEvent += localEvent;
【讨论】:
如果事件是由另一个类发布的,您不能 - 至少,不可靠。虽然我们通常认为事件只是一个委托变量,但它实际上只是一对方法:添加和删除(或订阅和取消订阅)。
如果是您自己的代码发布事件,这很容易 - 您可以让添加/删除访问器做任何您喜欢的事情。
看看my article on events 看看是否对您有帮助。如果没有,请提供更多关于您想要做什么的详细信息,指定您可以修改哪些代码位以及您不能修改哪些代码。
【讨论】:
如果您需要检查外部类事件的订阅者:
EventHandler e = typeof(ExternalClass)
.GetField(nameof(ExternalClass.Event), BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(instanceOfExternalClass) as EventHandler;
if (e != null)
{
Delegate[] subscribers = e.GetInvocationList();
}
【讨论】:
更新(感谢评论者):委托不变性意味着克隆对分配没有任何作用。
当一个人写作时:
myDelegate += AHandler
一个全新的委托实例被创建并分配给myDelegate。
因此,如果没有 Clone 调用,下面的代码将完全一样地工作。
MulticastDelegate(底层类型)有一个Clone 方法。
为了能够访问底层委托,您可能需要避免使用 event 关键字生成的常用助手,并直接管理事物(自定义添加和删除访问器)。
显示这个:
public class Program {
public delegate void MyDelegate(string name);
public event MyDelegate EventOne;
public void HandlerOne(string name) => Console.WriteLine($"This is handler one: {name}");
public void HandlerTwo(string name) => Console.WriteLine($"This is handler two: {name}");
public void HandlerThree(string name) => Console.WriteLine($"This is handler three: {name}");
public void Run() {
EventOne += HandlerOne;
EventOne += HandlerTwo;
Console.WriteLine("Before clone");
EventOne("EventOne");
MyDelegate eventTwo = (MyDelegate)EventOne.Clone();
MyDelegate eventTwo = EventOne;
Console.WriteLine("After clone copy");
EventOne("EventOne");
eventTwo("eventTwo");
Console.WriteLine("Change event one to show it is different");
EventOne += HandlerThree;
EventOne("EventOne");
eventTwo("eventTwo");
}
private static void Main(string[] args) => (new Program()).Run();
}
【讨论】: