C# 将事件分配给事件处理程序的两种不同类型之间的差异

C# 将事件分配给事件处理程序的两种不同类型之间的差异,c#,events,com,C#,Events,Com,我在中看到了这个示例代码,所以说一个实践是坏的,另一个是好的。但我不明白为什么? 事实上,我得到了著名的RCW COM对象错误,那篇文章说这可能是一个原因 public class SomeClass { private Interop.ComObjectWrapper comObject; private event ComEventHandler comEventHandler; public SomeClass() { comObject

我在中看到了这个示例代码,所以说一个实践是坏的,另一个是好的。但我不明白为什么? 事实上,我得到了著名的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
    }
}


编辑:这里是到源代码的链接:

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

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

任何委托都包含两部分:
object
类型的
Target
和指向特定方法的方法指针。如果
Target
null
,则回调指向静态方法

不可能有类型为
Target
的委托。有所谓的委托,但它是在委托之上实现的,而不是普通委托

在字段中存储事件处理程序将没有帮助。第一部分 内部事件实现是指订阅事件后:

comObject.SomeEvent += EventCallback;
comObject
对象隐式地包含对
SomeClass
对象的强引用无论您使用的是哪种订阅技术,也不管ComObject是否是COM对象包装器,这都是正确的

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

在字段中存储事件处理程序将没有帮助。第二部分 但是,如果我的假设不正确,并且
ComObjectWrapper
提供了一些弱事件模式的概念,那么在字段中保存事件处理程序将毫无帮助

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

private event ComEventHandler comEventHandler;
... 
comEventHandler = new ComEventHandler(EventCallback);
在当前字段中保存回调(基本上我们可以将私有事件视为简单的委托字段)不会改变现有行为

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

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

私人某类某类

公共部分 { //这与存储委托基本相同 //在comEventHandler领域 someClass=这个; }

SomeClass
中存储强引用不会延长当前对象的生存期。
这意味着如果
comObject包装器
不会保存对
SomeClass
的强引用,则在
comEventHandler
中存储事件处理程序的对象不会延长某个类的生存期,并且不会阻止
SomeClass
进行垃圾收集

结论 在私有字段中存储事件处理程序不会延长对象的生存期,也不会阻止它进行垃圾收集

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

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

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

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

你能链接到有问题的示例代码吗?谁在断言一个是好的,一个是坏的;如果这是公开的和在线的,你能链接到他们声明的地方吗?我会这样做:
comObject.SomeEvent+=EventCallback。C#编译器会自动暗示并添加新的ComEventHandler
。@Servy:用链接更新了问题@更多细节请参见我的答案。非常感谢谢尔盖的回答。我学到了一些新东西。回到主要问题,您提到:“在应用程序中访问事件持有者之前,事件订阅者不会死亡。”您能否就如何定位问题并解决问题提出一些调试技术或某种解决方案?您应该看看本文中提到的其他评论。若要检查对象生存期是否存在问题,可以将此对象的实例添加到对象的静态列表:private static list _neverdinglist=new list();//在方法_neverdinglist.中添加(this);如果这没有帮助,这将意味着你有一些其他问题,如公寓问题或其他东西。