我正在使用一个 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)由两部分组成:
- 方法引用
- 对象引用(目标)
当事件被定义它的对象调用时,如触发“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/