C#:什么破坏了我的 NativeWindow 对象,为什么?

标签 c# garbage-collection subclassing nativewindow

我正在使用一个 NativeWindow 对象来子类化一个非托管窗口的消息泵,目的是拦截它的消息。

代码结构看起来像这样(伪 C#,请原谅小的语法问题):

class AppSubclass : Control {

    class SpecialAppWndProc : NativeWindow {

        protected override void WndProc(ref Message m) {

            switch (m.msg) {

                // do stuff
                if (SpecialEvent != null) SpecialEvent(x);
            }

            base.WndProc(ref m);

        }

        public delegate void SpecialEventHandler(int Xstart);
        public event SpecialEventHandler SpecialEvent;

        ~SpecialAppWndProc() {

            DebugTrace("Help! Save me!");

        }

    }

    private SpecialAppWndProc specialAppWndProc = new SpecialAppWndProc();

    private void StartMonitoring() {

        // do stuff


        specialAppWndProc.AssignHandle(hWndUnmanagedWindow);
        specialAppWndProc.SpecialEvent += new SpecialAppWndProc.SpecialEventHandler(specialAppWndProc_SpecialEvent);

    }

    /* ... event handler ... */

    public AppSubClass() {

        StartMonitoring();

    }

}

现在,我认为设置一个事件监听器足以阻止垃圾收集器,如果我的对象因为 GC 而死亡。如果不是,是否有可能追踪如何以及为什么?我从来不知道 .Net 会因为代码错误而杀死对象(异常和偶尔的静默失败似乎是事情的一般要点)而且我不知道主机应用程序如何或为什么(我的应用程序是一个 COM 服务器用于非托管代码)也会有足够的知识来杀死我的对象。

鉴于该对象看似随机死亡(我无法确定一组特定的事件,只是它在调用 StartMonitoring() 后不到一秒到几分钟的任何时间死亡。

看起来 HandleRef 可能会解决我的问题,但是我不清楚如何在这种情况下使用它,而且我想不出如何将它放入我的代码中(除了可能在 AppSubclass 级别声明一个,然后将其分配给 SpecialAppWndProc 对象。

那么,如何防止我的对象在我准备好让它死掉之前死掉?

最佳答案

您需要存储对对象的引用。

事件在另一个方向起作用,使事件将触发的对象保持事件状态,而不是事件源。

如果您向 GC.Collect 和 GC.WaitForPendingFinalizers 添加一些调用,我敢肯定您会很快引发问题。

让我进一步充实我的回答。

事件基本上只是伪装的委托(delegate)。伪装只是删除了与委托(delegate)相关的一些功能,因此外部代码无法对底层委托(delegate)做任何它想做的事情,但本质上,它是一个普通的委托(delegate)。

那么什么是委托(delegate)?引用单个方法的委托(delegate)由两部分组成:

  1. 方法引用
  2. 对象引用(目标)

当事件被定义它的对象调用时,如触发“Button.Click”事件,特定对象(如 Form1 的实例)将触发特定方法(例如 bt_Click)。

因此,事件包含一个向外的引用,指向定义该方法的对象。该事件不会对该其他对象执行任何操作,因此其他对象(如我上面示例中的 Form1)不会以任何方式与此事件相关,并包含对该对象的引用。

所以在你的情况下,假设你有这段代码:

AppSubclass app = new AppSubclass(); // this starts monitoring

如果您现在让该变量超出范围,则该对象符合收集条件,因为没有任何对象持有对它的引用。 AppSubclass 和 SpecialAppWndProc 之间存在内部引用并不重要,两种方式都可能存在引用,但如果没有外部代码持有对它的引用,则这些对象符合收集条件。

因此您需要在某处存储对对象的引用,以避免被收集。

要回答您最初的问题,即“C#:什么正在破坏我的 NativeWindow 对象,为什么?”,答案是垃圾收集器破坏了您的 NativeWindow 对象,原因是没有根目录引用它(根引用,我指的是存储在静态变量中的引用、其他根引用的成员变量,或作为事件方法中的局部变量。)

关于C#:什么破坏了我的 NativeWindow 对象,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1949897/

相关文章:

c# - 具有 IDisposable 的无限状态机

c# - 从在单独线程上运行的方法返回列表

java - 如何使用具体参数进行子类化

C# 如何在值太大时对 int 进行排序

c# - WaitHandle.WaitAny 每次调用时都会分配 WaitHandle[] 的副本

memory-leaks - GenServer 进程的内存泄漏

java - 从pyspark手动调用spark的垃圾回收

design-patterns - 单例测试和子类化

python - 如果您对 API 不满意该怎么办?

c# - 将 Windows Phone 8 应用程序连接到远程 mysql 数据库