gpt4 book ai didi

c# - 将事件分配给事件处理程序的两种不同类型的区别

转载 作者:行者123 更新时间:2023-11-30 15:36:37 26 4
gpt4 key购买 nike

我在 SO 中看到这个示例代码,它说一种做法不好,另一种做法很好。但我不明白为什么?事实上,我遇到了那个著名的 RCW COM 对象错误,并且那个帖子说这可能是一个原因。

public class SomeClass
{
private Interop.ComObjectWrapper comObject;
private event ComEventHandler comEventHandler;

public SomeClass()
{
comObject = new Interop.ComObjectWrapper();

// NO - BAD!
comObject.SomeEvent += new ComEventHandler(EventCallback);

// YES - GOOD!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler
}

public void EventCallback()
{
// DO WORK
}

编辑:这里是源链接:COM object that has been separated from its underlying RCW cannot be used

最佳答案

我认为这两个代码片段是相同的,我们在这里没有任何关于强引用/弱引用的问题。

背景

首先,如果我们的 Interop.ComObjectWrapper 提供 CLR 事件(即在委托(delegate)中存储事件处理程序的事件),我们肯定会从 ComObjectWrapper 获得一个强引用到我们的目标。

任何委托(delegate)都包含两部分:类型为objectTarget 和指向特定方法的方法指针。如果 Targetnull,则回调指向静态方法。

Target 类型为 WeakReference 的委托(delegate)是不可能的.有所谓的Weak Event Pattern但它在 EventManager 之上实现而不是普通代表。

在字段中存储事件处理程序无济于事。第 1 部分

内部事件实现是指订阅事件后:

comObject.SomeEvent += EventCallback;

comObject 对象隐含地持有对 SomeClass 对象的强引用。 无论您使用何种订阅技术,无论 ComObject 是否为 COM 对象包装器,都是如此。

订阅事件会在生命周期方面增加两个对象之间的隐式依赖性。这就是为什么 .NET 世界中最常见的内存泄漏是由订阅长生命周期对象的事件引起的。 在应用程序中访问事件持有者之前,事件订阅者不会死亡。

在字段中存储事件处理程序无济于事。第二部分

但是如果我的假设不成立并且 ComObjectWrapper 提供了一些弱事件模式的概念,那么在现场保存事件处理程序将无济于事。

让我们回顾一下事件关键字的含义:

private event ComEventHandler comEventHandler;
...
comEventHandler = new ComEventHandler(EventCallback);

在当前字段中保存回调(基本上我们可以将私有(private)事件视为一个简单的委托(delegate)字段)不会改变现有行为。

我们已经知道委托(delegate)是一个简单的对象,它存储对 Target 对象(即 SomeClass 对象)的引用和一个方法(即 public void EventCallBack())。这意味着在字段中存储额外的委托(delegate)会从 SomeClass 本身添加对 SomeClass 的额外引用。

基本上,在字段中存储事件处理程序在语义上等同于在 SomeClass 中存储附加引用:

私有(private)的一些类一些类;

公共(public) SomeClaas(){ //这与存储委托(delegate)基本相同 //在 comEventHandler 字段中 一些类=这个;

SomeClass 中存储强引用不会延长当前对象的生命周期。 这意味着如果 ComObjectWrapper 不会持有强引用引用 comEventHandler 中存储事件处理程序的 SomeClass 对象不会延长 SomeClass 的生命周期,也不会阻止 SomeClass 进行垃圾回收。

结论

将事件处理程序存储在私有(private)字段中不会延长对象的生命周期,也不会阻止它进行垃圾回收。

这就是为什么以下代码片段在对象生命周期方面没有区别的原因:

    // GOOD!
comObject.SomeEvent += new ComEventHandler(EventCallback);

// EVEN BETTER!
comObject.SomeEvent += EventCallback;

// NOT GOOD, BECAUSE WAN'T HELP!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler

关于c# - 将事件分配给事件处理程序的两种不同类型的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13567692/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com