我需要处理撤销注册事件吗?(复制)

时间:2023-02-09 16:01:48

This question already has an answer here:

这个问题已经有了答案:

Say I have two classes, and neither of them are GUI components. Class A is a short lived object that registers for an event declared by a long lived object B. For example

假设我有两个类,它们都不是GUI组件。类A是一个短生存对象,它为一个长生存对象b声明的事件注册

public A(B b)
{
   b.ChangeEvent += OnChangeEvent;
}

If A never deregisters from B's event, will A never be garbage collected? Does A need a Dispose method just to deregister from B's event?

如果A从未参加过B的活动,A将永远不会被垃圾收集?A是否需要一个处理方法来从B的事件中删除?

There is also a related second question. If A and B should both live for the entire execution time of the application, does A need to deregister?

还有一个相关的第二个问题。如果A和B都应该在应用程序的整个执行时间内生存,那么A是否需要取消注册?

3 个解决方案

#1


3  

To your first question: Yes. B has a reference to A. That way A will live as long as B. This is a nice way to loose memory in a UI app if you e.g. register with an event like App.OnIdle.

对于你的第一个问题:是的。如果你注册了app . onidle这样的事件,这是一个很好的在UI应用程序中释放内存的方法。

To the second: At the end everything will be killed.

第二点:到最后,一切都将被毁灭。

#2


1  

The proper place to disconnect the event would, as you suspect, be in the IDisposable.Dispose method of A. There isn't really any good alternative. It would be useless to try to disconnect the event within A's finalizer/destructor, since the only way A would ever be eligible for garbage collection prior to its disconnecting from B would be for B to become itself eligible for garbage collection; once that has happened, the subscription would become a moot point so it wouldn't matter whether it was cleaned up or not.

正如您所怀疑的,断开事件连接的适当位置应该位于IDisposable语句中。a的处置方法真的没有什么好办法。尝试断开A的终结器/析构函数内的事件是无用的,因为在A与B断开连接之前,唯一符合条件进行垃圾收集的方法是让B自己成为符合条件的垃圾收集者;一旦这种情况发生,订阅将成为一个不重要的点,因此它是否被清理将无关紧要。

If it's necessary for events from abandoned short-lived subscribers to be cleaned up within the lifetime of a long-lived publisher, there are ways of doing that if the publishing and subscribing classes cooperate. For example, the event subscriber's public face can be a wrapper object which holds a reference to the actual event subscriber, with the subscriber itself not holding a strong reference to that public object. Under that scenario, the event subscription would not prevent the public object from falling out of scope and becoming eligible for finalization. A finalizer in the public object could notify the subscribing object that the subscription would no longer be needed and it should unsubscribe. Since such notification would arrive asynchronously, the object publishing the subscription would have to offer a means by which subscribers could be asynchronously unsubscribed. This could be done by a normal "unsubscribe" request, provided that the publishing event guaranteed it to be non-blocking and thread-safe; unfortunately, most events offer no such guarantee.

如果在一个长期的发布者的生命周期内,从被抛弃的短时间订阅服务器上的事件需要清理,那么,如果发布和订阅类合作,就有办法做到这一点。例如,事件订阅方的公共面可以是一个包装器对象,它持有对实际事件订阅方的引用,而订阅方本身并不持有对该公共对象的强引用。在这种情况下,事件订阅不会阻止公共对象超出范围并有资格进行终结。公共对象中的终结器可以通知订阅对象不再需要订阅,并且应该取消订阅。由于此类通知将异步到达,发布订阅的对象必须提供一种方式,通过这种方式可以异步取消订阅。这可以通过一个正常的“取消订阅”请求来完成,前提是发布事件保证它是无阻塞和线程安全的;不幸的是,大多数事件都没有这样的保证。

#3


0  

If B holds a reference to A, A will not get Garbage Collected unless B is also eligible for Garbage Collection.

如果B持有对a的引用,a将不会得到垃圾收集,除非B也有资格进行垃圾收集。

You shouldn't need a Dispose method for this. Once B has no references pointing to it either, the Garbage Collector will be smart enough to dispose both B and A.

您不应该为此需要一个Dispose方法。一旦B也没有指向它的引用,垃圾收集器将足够聪明地处理B和A。

If they are both alive for the life of the application, you don't need to deregister the event.

如果它们在应用程序的生命周期中都是活动的,则不需要撤销事件。

#1


3  

To your first question: Yes. B has a reference to A. That way A will live as long as B. This is a nice way to loose memory in a UI app if you e.g. register with an event like App.OnIdle.

对于你的第一个问题:是的。如果你注册了app . onidle这样的事件,这是一个很好的在UI应用程序中释放内存的方法。

To the second: At the end everything will be killed.

第二点:到最后,一切都将被毁灭。

#2


1  

The proper place to disconnect the event would, as you suspect, be in the IDisposable.Dispose method of A. There isn't really any good alternative. It would be useless to try to disconnect the event within A's finalizer/destructor, since the only way A would ever be eligible for garbage collection prior to its disconnecting from B would be for B to become itself eligible for garbage collection; once that has happened, the subscription would become a moot point so it wouldn't matter whether it was cleaned up or not.

正如您所怀疑的,断开事件连接的适当位置应该位于IDisposable语句中。a的处置方法真的没有什么好办法。尝试断开A的终结器/析构函数内的事件是无用的,因为在A与B断开连接之前,唯一符合条件进行垃圾收集的方法是让B自己成为符合条件的垃圾收集者;一旦这种情况发生,订阅将成为一个不重要的点,因此它是否被清理将无关紧要。

If it's necessary for events from abandoned short-lived subscribers to be cleaned up within the lifetime of a long-lived publisher, there are ways of doing that if the publishing and subscribing classes cooperate. For example, the event subscriber's public face can be a wrapper object which holds a reference to the actual event subscriber, with the subscriber itself not holding a strong reference to that public object. Under that scenario, the event subscription would not prevent the public object from falling out of scope and becoming eligible for finalization. A finalizer in the public object could notify the subscribing object that the subscription would no longer be needed and it should unsubscribe. Since such notification would arrive asynchronously, the object publishing the subscription would have to offer a means by which subscribers could be asynchronously unsubscribed. This could be done by a normal "unsubscribe" request, provided that the publishing event guaranteed it to be non-blocking and thread-safe; unfortunately, most events offer no such guarantee.

如果在一个长期的发布者的生命周期内,从被抛弃的短时间订阅服务器上的事件需要清理,那么,如果发布和订阅类合作,就有办法做到这一点。例如,事件订阅方的公共面可以是一个包装器对象,它持有对实际事件订阅方的引用,而订阅方本身并不持有对该公共对象的强引用。在这种情况下,事件订阅不会阻止公共对象超出范围并有资格进行终结。公共对象中的终结器可以通知订阅对象不再需要订阅,并且应该取消订阅。由于此类通知将异步到达,发布订阅的对象必须提供一种方式,通过这种方式可以异步取消订阅。这可以通过一个正常的“取消订阅”请求来完成,前提是发布事件保证它是无阻塞和线程安全的;不幸的是,大多数事件都没有这样的保证。

#3


0  

If B holds a reference to A, A will not get Garbage Collected unless B is also eligible for Garbage Collection.

如果B持有对a的引用,a将不会得到垃圾收集,除非B也有资格进行垃圾收集。

You shouldn't need a Dispose method for this. Once B has no references pointing to it either, the Garbage Collector will be smart enough to dispose both B and A.

您不应该为此需要一个Dispose方法。一旦B也没有指向它的引用,垃圾收集器将足够聪明地处理B和A。

If they are both alive for the life of the application, you don't need to deregister the event.

如果它们在应用程序的生命周期中都是活动的,则不需要撤销事件。