我有一个类,它提供了一个适配器来连接COM对象。这是一个简化版本的代码实现:
问题在于OnClose事件处理程序使两个对象都保持活动状态。这两个对象应该具有相同的生命周期,因此当一个对象消失时,另一个对象也应该消失,即没有人会保持一个对象的存活并期望另一个对象消失。
我尝试使用弱引用进行实验:
如果未注册OnClose,则两个对象都会被回收。如果注册了OnClose,则两个对象都不会被回收。如何确保这对对象可收集而不失去事件?
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 { get { return this.doc != null; } }
}
问题在于OnClose事件处理程序使两个对象都保持活动状态。这两个对象应该具有相同的生命周期,因此当一个对象消失时,另一个对象也应该消失,即没有人会保持一个对象的存活并期望另一个对象消失。
我尝试使用弱引用进行实验:
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 was not collected");
if (weak2.Target != null)
Console.WriteLine("Wrapper was not collected");
如果未注册OnClose,则两个对象都会被回收。如果注册了OnClose,则两个对象都不会被回收。如何确保这对对象可收集而不失去事件?
this.doc
设为null
之前,尝试调用Marshal.ReleaseComObject(this.doc)
。请务必先阅读此文:http://blogs.msdn.com/b/visualstudio/archive/2010/03/01/marshal-releasecomobject-considered-dangerous.aspx。 - noseratio - open to workOnClose
以参数形式接收文档来打破循环,这样事件处理程序就不必保留对它的引用。 - acelentCOMDocument
,该处理程序仅对实际处理程序具有弱引用。如果弱引用不为null
,则"弱"处理程序的OnClose
将调用实际处理程序的OnClose
。实际处理程序可以保留对COMDocument
的引用。 - acelent