C# 如何获得事件的订阅者?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/572647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get the subscribers of an event?
提问by weiqure
I need to copy the subscribers of one event to another event. Can I get the subscribers of an event (like MyEvent[0] returning a delegate)?
我需要将一个事件的订阅者复制到另一个事件。我可以获取事件的订阅者吗(比如 MyEvent[0] 返回一个委托)?
If this is not possible I would use the add accessor to add the delegates to a list. Would that be the best solution?
如果这是不可能的,我将使用 add 访问器将委托添加到列表中。这会是最好的解决方案吗?
采纳答案by Marc Gravell
C# events/delegates are multicast, so the delegate is itselfa list. From within the class, to get individual callers, you can use:
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
}
}
However, to assign all at once, just use += or direct assignment:
但是,要一次分配所有内容,只需使用 += 或直接分配:
SomeType other = ...
other.SomeEvent += localEvent;
回答by Richard
Update (thanks to commenters): delegate immutability means that cloning achieves nothing over an assignment.
更新(感谢评论者):委托不变性意味着克隆对分配没有任何帮助。
When one writes:
当一个人写道:
myDelegate += AHandler
A completely new delegate instance is created and assigned to myDelegate
.
一个全新的委托实例被创建并分配给myDelegate
.
Therefore, the code below would work exactly the same without the Clone call.
因此,如果没有 Clone 调用,下面的代码将完全相同。
MulticastDelegate
(the underlying type) has a Clone
method.
MulticastDelegate
(底层类型)有一个Clone
方法。
To be able to get to the underlying delegate you might need to avoid the usual helper that the event keyword generates, and manage things directly (custom add and remove accessors).
为了能够访问底层委托,您可能需要避免使用 event 关键字生成的常用助手,并直接管理事物(自定义添加和删除访问器)。
To show this:
要显示这一点:
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();
}
回答by Jon Skeet
If the event is one published by another class, you can't - at least, not reliably. While we often think of an event as being just a delegate variable, it's actually just a pair of methods: add and remove (or subscribe and unsubscribe).
如果该事件是由另一个类发布的,则您不能 - 至少,不可靠。虽然我们经常认为一个事件只是一个委托变量,但它实际上只是一对方法:添加和删除(或订阅和取消订阅)。
If it's your own code that's publishing the event, it's easy - you can make the add/remove accessors do whatever you like.
如果发布事件的是您自己的代码,则很容易 - 您可以让添加/删除访问器执行您喜欢的任何操作。
Have a look at my article on eventsand see if that helps you. If not, please give more details about what you want to do, specifying which bits of code you're able to modify and which you aren't.
看看我关于事件的文章,看看是否对你有帮助。如果没有,请提供有关您想要做什么的更多详细信息,指定您可以修改哪些代码位,哪些不能。
回答by Monsignor
In case you need to examine subscribers of an external class' event:
如果您需要检查外部类事件的订阅者:
EventHandler e = typeof(ExternalClass)
.GetField(nameof(ExternalClass.Event), BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(instanceOfExternalClass) as EventHandler;
if (e != null)
{
Delegate[] subscribers = e.GetInvocationList();
}