我是否必须在终结器中删除eventHandlers?

时间:2021-12-27 00:07:48

I have a model class that has a Saved event. The idea is that if two viewmodels use that model object, if one of them changes it, the other will be updated.

我有一个具有Saved事件的模型类。这个想法是,如果两个视图模型使用该模型对象,如果其中一个更改它,则另一个将更新。

Do I have to remove the event handler when I am no longer using its view model? Here is my code:

当我不再使用其视图模型时,是否必须删除事件处理程序?这是我的代码:

protected AbstractEntityViewModel(AbstractEntity ae)
{
    this.ae = ae;

    ae.Saved += delegate(object o, EventArgs e) 
    { 
        base.OnPropertyChanged(null);
    };
}

Is this ok, or do I need to change this so that I can -= get rid of the delegate when the viewmodel is no longer used?

这是好的,还是我需要更改它以便我可以 - =在不再使用viewmodel时删除委托?

3 个解决方案

#1


3  

Long and short of it is yes. The secondary object can not be disposed of if the AbstractEntity object still has a reference to it. IF there is a chance that the object will be disposed and the Event is still around (this holds true for static events too) then you need to manually remove the eventhandler or the object will not be disposed.

它的长短是肯定的。如果AbstractEntity对象仍然具有对它的引用,则不能处理辅助对象。如果有可能放置对象并且事件仍然存在(这也适用于静态事件),那么您需要手动删除事件处理程序,否则将不会处置该对象。

#2


1  

Events can be though of as being a primitive observer implementation: The subject retains a handler to every subscribed observer, meaning they are unable to be garbage collected. To allow the observer to be garbage collected, it must be removed as an observer from the subject.

事件可以是一个原始的观察者实现:主体保留每个订阅观察者的处理程序,这意味着它们不能被垃圾收集。为了允许观察者被垃圾收集,必须将其作为观察者从主体中移除。

The only time where event handlers do not need to be manually removed are when the subject and the observer are the same instance, as the garbage collector will detect the circular reference and subsequently finalize the object.

事件处理程序不需要手动删除的唯一时间是主题和观察者是同一个实例,因为垃圾收集器将检测循环引用并随后完成对象。

#3


0  

Direction of event References

To know whether you really need to detach the event handler, you've first got to understand that:

要知道您是否真的需要分离事件处理程序,您首先必须了解:

ae.Saved += delegate(object o, EventArgs e) 
{ 
    base.OnPropertyChanged(null);
};

means ae is now referencing this. So the object with the event is referencing the object with the event handler. It's not the other way around (event handler referencing event).

意味着ae现在正在引用它。因此,事件的对象是使用事件处理程序引用对象。它不是相反的方式(事件处理程序引用事件)。

Objects not referenced by GC root can be collected

Furthermore, while ideally objects to be garbage collected are not referenced by any other objects, that is not strictly necessary:

此外,理想情况下,任何其他对象都不会引用要进行垃圾回收的对象,但这并非绝对必要:

The garbage collector can collect all objects which are not referenced by a GC root in any way (path). This means if you've got an insular graph of objects (objects referencing other objects of the graph, but there is no object outside the graph which is referencing an object inside the graph [no GC root either]), then the entire object graph will eventually be garbage collected. The more intertwined the graph is, the more expensive it is for the GC to collect it. Detaching event handlers helps in dissolving such graphs more speedily.

垃圾收集器可以以任何方式(路径)收集GC根未引用的所有对象。这意味着如果你有一个对象的孤立图(引用图的其他对象的对象,但图中没有引用图中对象的对象[也没有GC根]),那么整个对象图最终将被垃圾收集。图表交织得越多,GC收集它的成本就越高。分离事件处理程序有助于更快地解散这些图形。

Correctly cleaning up objects

.Net does not feature Destructors. Instead there is the IDisposable pattern and finalizers (see Implementing Finalize and Dispose to Clean Up Unmanaged Resources).

.Net没有Destructors功能。相反,有IDisposable模式和终结器(请参阅实现最终化和处理以清理非托管资源)。

Long story short:

长话短说:

  • Finalization methods (~Foo () { } for class Foo) are needed when an object manages unmanaged resources. They are called by the garbage collector when the GC is collecting the object. So the exact moment is not up to you.
  • 当对象管理非托管资源时,需要终结方法(类Foo的~Foo(){}。当GC收集对象时,垃圾收集器会调用它们。所以确切的时刻不取决于你。

  • Disposable pattern can be used to clean-up managed as well as unmanaged resources. If the object has got unmanaged resources, it must still have a finalizer. Why? The Dispose() method is called by you. There is no guarantee that it's being executed. If the application fails to call the Dispose() method, there's still the GC which calls finalize. So basically doing unmanaged-resource cleanup in Dispose is just a performance improvement (which, under some circumstances, may be very important, unless you want to plug in a few more gigabytes of RAM into the computer...).
  • 一次性模式可用于清理托管和非托管资源。如果对象具有非托管资源,则它仍必须具有终结器。为什么?您调用Dispose()方法。无法保证它正在被执行。如果应用程序无法调用Dispose()方法,那么仍然会调用finalize的GC。所以基本上在Dispose中进行非托管资源清理只是一种性能改进(在某些情况下,这可能非常重要,除非你想在计算机中插入几兆字节的RAM ......)。

If you plan to use a finalizer i absolutely urge you to read the docs on it, because there's quite a few things which i didn't cover here. See Implementing Finalize and Dispose to Clean Up Unmanaged Resources

如果你打算使用终结器,我绝对敦促你阅读它上面的文档,因为这里有很多我没有涉及的内容。请参阅实现Finalize和Dispose以清理非托管资源

Your example

To come back to your example, after you construct a AbstractEntityViewModel, it will stay alive as long as the AbstractEntity you've passed to the AbstractEntityViewModel stays alive and vice versa. But when neither of those two are referenced by a GC root, both of them are garbage collected.

回到您的示例,在构造AbstractEntityViewModel之后,只要您传递给AbstractEntityViewModel的AbstractEntity保持活动状态,它就会保持活动状态,反之亦然。但是当这两个都没有被GC根引用时,它们都被垃圾收集。

If you detach the event handler, the AbstractEntityViewModel (or rather it's concrete sub-class instance) can be garbage collected even if the AbstractEntity can't.

如果分离事件处理程序,即使AbstractEntity不能,也可以对AbstractEntityViewModel(或者更具体的子类实例)进行垃圾回收。

Also see: Understanding Garbage Collection in .NET

另请参阅:了解.NET中的垃圾收集


#1


3  

Long and short of it is yes. The secondary object can not be disposed of if the AbstractEntity object still has a reference to it. IF there is a chance that the object will be disposed and the Event is still around (this holds true for static events too) then you need to manually remove the eventhandler or the object will not be disposed.

它的长短是肯定的。如果AbstractEntity对象仍然具有对它的引用,则不能处理辅助对象。如果有可能放置对象并且事件仍然存在(这也适用于静态事件),那么您需要手动删除事件处理程序,否则将不会处置该对象。

#2


1  

Events can be though of as being a primitive observer implementation: The subject retains a handler to every subscribed observer, meaning they are unable to be garbage collected. To allow the observer to be garbage collected, it must be removed as an observer from the subject.

事件可以是一个原始的观察者实现:主体保留每个订阅观察者的处理程序,这意味着它们不能被垃圾收集。为了允许观察者被垃圾收集,必须将其作为观察者从主体中移除。

The only time where event handlers do not need to be manually removed are when the subject and the observer are the same instance, as the garbage collector will detect the circular reference and subsequently finalize the object.

事件处理程序不需要手动删除的唯一时间是主题和观察者是同一个实例,因为垃圾收集器将检测循环引用并随后完成对象。

#3


0  

Direction of event References

To know whether you really need to detach the event handler, you've first got to understand that:

要知道您是否真的需要分离事件处理程序,您首先必须了解:

ae.Saved += delegate(object o, EventArgs e) 
{ 
    base.OnPropertyChanged(null);
};

means ae is now referencing this. So the object with the event is referencing the object with the event handler. It's not the other way around (event handler referencing event).

意味着ae现在正在引用它。因此,事件的对象是使用事件处理程序引用对象。它不是相反的方式(事件处理程序引用事件)。

Objects not referenced by GC root can be collected

Furthermore, while ideally objects to be garbage collected are not referenced by any other objects, that is not strictly necessary:

此外,理想情况下,任何其他对象都不会引用要进行垃圾回收的对象,但这并非绝对必要:

The garbage collector can collect all objects which are not referenced by a GC root in any way (path). This means if you've got an insular graph of objects (objects referencing other objects of the graph, but there is no object outside the graph which is referencing an object inside the graph [no GC root either]), then the entire object graph will eventually be garbage collected. The more intertwined the graph is, the more expensive it is for the GC to collect it. Detaching event handlers helps in dissolving such graphs more speedily.

垃圾收集器可以以任何方式(路径)收集GC根未引用的所有对象。这意味着如果你有一个对象的孤立图(引用图的其他对象的对象,但图中没有引用图中对象的对象[也没有GC根]),那么整个对象图最终将被垃圾收集。图表交织得越多,GC收集它的成本就越高。分离事件处理程序有助于更快地解散这些图形。

Correctly cleaning up objects

.Net does not feature Destructors. Instead there is the IDisposable pattern and finalizers (see Implementing Finalize and Dispose to Clean Up Unmanaged Resources).

.Net没有Destructors功能。相反,有IDisposable模式和终结器(请参阅实现最终化和处理以清理非托管资源)。

Long story short:

长话短说:

  • Finalization methods (~Foo () { } for class Foo) are needed when an object manages unmanaged resources. They are called by the garbage collector when the GC is collecting the object. So the exact moment is not up to you.
  • 当对象管理非托管资源时,需要终结方法(类Foo的~Foo(){}。当GC收集对象时,垃圾收集器会调用它们。所以确切的时刻不取决于你。

  • Disposable pattern can be used to clean-up managed as well as unmanaged resources. If the object has got unmanaged resources, it must still have a finalizer. Why? The Dispose() method is called by you. There is no guarantee that it's being executed. If the application fails to call the Dispose() method, there's still the GC which calls finalize. So basically doing unmanaged-resource cleanup in Dispose is just a performance improvement (which, under some circumstances, may be very important, unless you want to plug in a few more gigabytes of RAM into the computer...).
  • 一次性模式可用于清理托管和非托管资源。如果对象具有非托管资源,则它仍必须具有终结器。为什么?您调用Dispose()方法。无法保证它正在被执行。如果应用程序无法调用Dispose()方法,那么仍然会调用finalize的GC。所以基本上在Dispose中进行非托管资源清理只是一种性能改进(在某些情况下,这可能非常重要,除非你想在计算机中插入几兆字节的RAM ......)。

If you plan to use a finalizer i absolutely urge you to read the docs on it, because there's quite a few things which i didn't cover here. See Implementing Finalize and Dispose to Clean Up Unmanaged Resources

如果你打算使用终结器,我绝对敦促你阅读它上面的文档,因为这里有很多我没有涉及的内容。请参阅实现Finalize和Dispose以清理非托管资源

Your example

To come back to your example, after you construct a AbstractEntityViewModel, it will stay alive as long as the AbstractEntity you've passed to the AbstractEntityViewModel stays alive and vice versa. But when neither of those two are referenced by a GC root, both of them are garbage collected.

回到您的示例,在构造AbstractEntityViewModel之后,只要您传递给AbstractEntityViewModel的AbstractEntity保持活动状态,它就会保持活动状态,反之亦然。但是当这两个都没有被GC根引用时,它们都被垃圾收集。

If you detach the event handler, the AbstractEntityViewModel (or rather it's concrete sub-class instance) can be garbage collected even if the AbstractEntity can't.

如果分离事件处理程序,即使AbstractEntity不能,也可以对AbstractEntityViewModel(或者更具体的子类实例)进行垃圾回收。

Also see: Understanding Garbage Collection in .NET

另请参阅:了解.NET中的垃圾收集