当事件被引发一次时,多次调用c#事件处理程序
下面是我的代码,首先是我提出事件的地方,第二部分是我在另一个类中使用它的地方。 它看起来很简单,但是日志显示即使事件被提升一次,事件也会在消耗此事件的类上触发20次以上。 有任何想法吗?
IBSerialPort
类:
public delegate void PacketReceivedHandler(object sender, PacketReceivedEventArgs e); public event PacketReceivedHandler OnPacketReceived; public class PacketReceivedEventArgs : EventArgs { public Packet PacketReceived { get; private set; } public PacketReceivedEventArgs(Packet packet) { PacketReceived = packet; } } // raise event if (OnPacketReceived != null) { Log("This is only called ONCE!"); PacketReceivedEventArgs args = new PacketReceivedEventArgs(data); OnPacketReceived(this, args); }
使用IBSerialPort
并使用其OnPacketReceived
事件的类:
IBSerialPort ibSerialPort = null; .. if (ibSerialPort == null) { Log("This is only called once"); ibSerialPort = IBSerialPort.Instance; ibSerialPort.OnPacketReceived += ibSerialPort_OnPacketReceived; } void ibSerialPort_OnPacketReceived(object sender, IBSerialPort.PacketReceivedEventArgs args) { Log("This is called ~25 times!!!!"); }
试试这个,这将取消注册任何普通用户:
ibSerialPort.OnPacketReceived -= ibSerialPort_OnPacketReceived; // unregister ibSerialPort.OnPacketReceived += ibSerialPort_OnPacketReceived; //register
这被称为多少次? 如果多次调用此函数,则会多次调用您的事件。
ibSerialPort.OnPacketReceived += ibSerialPort_OnPacketReceived;
作为测试,您可以在添加之前删除委托:
ibSerialPort.OnPacketReceived -= ibSerialPort_OnPacketReceived; ibSerialPort.OnPacketReceived += ibSerialPort_OnPacketReceived;
我想知道你的类是否使用了定义ibSerialPort_OnPacketReceived
的类(即使在单独的实例中)25次,你认为你正在释放它。 考虑以下代码:
class EventSender { public Action MyEvent; } class Subscriber { public void OnEvent() { Console.WriteLine("OnEvent"); } } class Program { static void Main(string[] args) { EventSender es = new EventSender(); Subscriber s = new Subscriber(); es.MyEvent += s.OnEvent; s = new Subscriber(); es.MyEvent += s.OnEvent; es.MyEvent(); Console.ReadKey(); } }
在这里,“OnEvent”将被打印两次。 即使看起来我已经发布了它的句柄,也会保留对订阅的引用。 这是由于代表们如何保留其订阅者列表。
如果这是问题,您每次都需要取消订阅:
es.MyEvent -= s.OnEvent
这应该在您丢失订阅者的句柄之前完成(即在s
超出范围或为null
)。 您可以考虑在subriber中跟踪事件源,并使用Dispose
方法取消订阅。
另外,正如其他人所说,你可以在订阅之前取消订阅:)我相信你现在已经拥有了所需的解决方案。
我有同样的问题,在同步方法中注册你的事件(我把它放在form_loaded中)
private async void Window_Loaded(object sender, RoutedEventArgs e) { RefreshHierarchy.COIDConflict += RefreshHierarchy_COIDConflict; }