.net - How to allow garbage collection on object with event handler connected to COM object -
i have class provides adapter com object. here's simplified version of it:
public class documentwrapper { private comdocument doc; public documentwrapper(comdocument doc) { this.doc = doc; this.doc.onclose += onclose; } private void onclose() { this.doc.onclose -= onclose; this.doc = null; } public bool isalive { { return this.doc != null; } } }
the problem onclose event handler keeping both objects alive. both objects should have same lifetime, when 1 goes away other should too, i.e. nobody keeping 1 alive , expecting other go away.
i did experimenting weak references:
comdocument com = createcomdocument(); var doc = new docwrapper(com); weakreference weak1 = new weakreference(com); weakreference weak2 = new weakreference(doc); gc.collect(2, gccollectionmode.forced); gc.waitforpendingfinalizers(); gc.collect(2, gccollectionmode.forced); if (weak1.target != null) console.writeline("com not collected"); if (weak2.target != null) console.writeline("wrapper not collected");
if onclose not registered, both objects collected. if onclose registered, neither object gets collected. how ensure pair of objects collectible without losing event?
the actual solution more complex because have worry multiple threads (the finalizer runs on background thread, , unregistering com event has invoke onto com thread, can trigger deadlock if i'm not careful). here's basic idea of how structure things make sure can garbage collected:
public class documentwrapper { private comdocument doc; private weakhandler closehandler; public documentwrapper(comdocument doc) { this.doc = doc; this.closehandler = new weakhandler(this); } ~documentwrapper() { if (closehandler != null) closehandler.unregister(); } public bool isalive { { return this.doc != null; } } private class weakhandler : idisposable { private weakreference owner; public weakhander(documentwrapper owner) { this.owner = new weakreference(owner); owner.doc.onclose += unregister(); } private void unregister() { if (owner == null) return; var target = owner.target documentwrapper; if (target != null && target.doc != null) { target.doc.onclose -= onclose; target.closehandler = null; gc.supressfinalize(target); } this.owner = null; } } }
Comments
Post a Comment