在什么情况下从必要的事件中分离?
我不确定我是否完全清楚附加对象中的事件的含义。
这是我目前的理解,正确或精细:
1.不需要分离附加到本地类事件
例子:
this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
public event EventHandler OnMyCustomEvent = delegate { };
我假设当你的对象被处理或被垃圾收集时,这些函数会被释放并自动从事件中分离出来。
2.必须分离附加到不再需要的对象(= null;)
示例:附加到计时器的Elapsed事件,您只响应一次。 我假设您需要将Timer存储在本地变量中,以便在事件触发后分离Elapsed事件。 因此,在本地方法范围内声明计时器会导致泄漏:
System.Timers.Timer myDataTimer = new System.Timers.Timer(1000); myDataTimer.Elapsed += new System.Timers.ElapsedEventHandler(myDataTimer_Elapsed);
3.将本地对象中的事件附加到您的class级不需要处理?
例如,如果您有一个ObservableCollection,您可以创建,监视并让它们死掉。 如果使用本地私有函数附加到CollectionChanged事件,当您的类被垃圾收集时,此函数是否会解除分配,导致ObservableCollection也被释放?
我确定我有停止使用对象并且无法从事件中分离的地方(例如,我制作的计时器示例),所以我正在寻找关于它是如何工作的更清楚的解释。
我认为你让它变得比它需要的更复杂。 你只需要记住两件事:
- 订阅活动时,活动的“所有者”(发布者)通常会保留对您订阅的代理人的引用。
- 如果使用实例方法作为委托的操作,则委托具有对其“目标”对象的引用。
这意味着如果你写:
publisher.SomeEvent += subscriber.SomeMethod;
除非您稍后取消订阅,否则订阅subscriber
将无法在publisher
之前进行垃圾回收。
请注意,在许多情况下, subscriber
就是this
:
publisher.SomeEvent += myDataTimer_Elapsed;
相当于:
publisher.SomeEvent += this.myDataTimer_Elapsed;
假设它是一个实例方法。
由于事件订阅没有反向关系 – 换句话说,订阅者不会保持发布者的活力。
顺便提一下,请参阅我关于事件和代表的文章以获取更多信息。
其余的防止垃圾收集的引用还有一个可能很明显的效果,但是在这个post中还没有说明; 附加的事件处理程序也将被执行。
我经历了几次。 一个是当我们有一个应用程序,它运行的时间越长越慢。 应用程序通过加载用户控件以动态方式创建用户界面。 容器使用户控件订阅环境中的某些事件,并且当控件被“卸载”时,其中一个未取消订阅。
一段时间后,这导致每次引发特定事件时都会执行大量事件侦听器。 当大量“睡眠”实例突然醒来并尝试对同一输入采取行动时,这当然会导致严重的竞争条件。
简而言之; 如果你编写代码来挂钩一个事件监听器; 确保在不再需要时立即释放。 我几乎敢于承诺,它将在未来的某个时刻让你免于至少一次头痛。
您必须取消订阅活动的相关案例如下:
public class A { // ... public event EventHandler SomethingHappened; } public class B { private void DoSomething() { /* ... */ } // instance method private void Attach(A obj) { obj.SomethingHappened += DoSomething(); } }
在这种情况下,当你处理一个B时, obj
的事件处理程序仍然会有一个悬空引用。 如果要回收B的内存,则需要B.DoSomething()
相关的事件处理程序中分离B.DoSomething()
。
如果事件订阅行看起来像这样,你可能遇到同样的事情,当然:
obj.SomethingHappened += someOtherObject.Whatever.DoSomething();
现在它是一个挂钩的someOtherObject
,不能被垃圾收集。
- 你可以在.NET中打开JPEG,添加文本和重新保存为JPEG吗?
- 什么是异步和等待,何时在Windows开发中使用这些?
- 如何理解EMCA 335中关于`.locals init`的这些段落?
- EF Code First:无法连接到SQL Server
- 使用HttpClient时如何在HttpContent中设置大字符串?
- WPF Listbox Virtualization创建DisconnectedItems
- 如何跨类使用TraceSource
- 处理和转换中哪一个更快int.Parse(),int.TryParse(),Convert.Int32()
- 每个WCF项目VS2013上的WcfSvcHost.exe访问冲突exception