【问题标题】:Releasing Multiple References to COM Objects Separately分别释放对 COM 对象的多个引用
【发布时间】:2014-12-09 10:18:33
【问题描述】:

我不太擅长管理 COM 对象。我已经阅读了相当多的内容,但我无法完全理解当您有两个引用指向一个 COM 对象并释放其中一个时会发生什么。考虑以下[半]假设:

我用 C# 为 Excel 工作簿创建了一个基本的包装类:

using ExcelInterop = Microsoft.Office.Interop.Excel;
...

public class WorkbookWrapper : IDisposable
{
    protected internal ExcelInterop.Workbook _wb;

    public WorkbookWrapper(ExcelInterop.Workbook workbook)
    {
        _wb = workbook;
    }

    public WorkbookWrapper(WorkbookWrapper workbookWrapper)
    {
        _wb = workbookWrapper._wb;
    }

    #region IDisposable

    // basic Dispose function which releases _wb COM Object (omitted to shorten post length)

    #endregion

    ...
}

对于我正在进行的一个特定项目,我发现有必要将一些附加信息附加到 WorkbookWrapper 对象,因此我对其进行了扩展:

class LinkingWorkbookWrapper : WorkbookWrapper
{
    internal string workbookGUID = null;

    internal LinkingWorkbookWrapper(WorkbookWrapper workbookWrapper, string GUID) : base(workbook)
    {
        workbookGUID = GUID;
    }

    ...
}

这个特定的类使用WorkbookWrapper(WorkbookWrapper) 构造函数来存储对互操作工作簿的新引用,这在使用如下函数时突然出现问题:

public static void ProcessAllCharts(WorkbookWrapper wbw)
{
    LinkingWorkbookWrapper lwbw = null;
    if(wbw is LinkingWorkbookWrapper)
        lwbw = (LinkingWorkbookWrapper)wbw;
    else
        lwbw = new LinkingWorkbookWrapper(wbw, GenerateGUID());

    //... do stuff ...
}

现在假设函数必须接受正常的WorkbookWrappers。 什么时候处理 lwbw 合适? 如果我在 ProcessAllCharts 结束时这样做,我可能会分离原始 wbw 中引用的 COM 对象来自其 RCW;另一方面,如果我不处理 lwbw,我会冒着将 COM 对象的引用留在以太中的风险。

【问题讨论】:

  • 你可以使用析构函数。
  • @IllidanS4 由于析构函数(如果我理解正确的话)将在包装器上,那不会产生大致相同的效果吗?包装器在ProcessAllCharts 末尾超出范围,此时即使它的成员仍然从其他地方引用,它也有资格进行垃圾收集。再说一次,我对这类事情不是很有信心,所以我可能完全错了,但(到目前为止)这是我的理解。
  • 叹息,让程序员摆脱困境是一项永无止境的艰巨任务。阅读this post,了解您认为需要这样做的原因。不要这样做,你永远不会做对。
  • 好吧,所以我认为最好只有一个密封的包装类来跟踪一个 COM 对象。然后根本不要在 ProcessAllCharts 的 and 处调用 Dispose,以确保该对象仍然可以在方法范围之外使用。
  • @IllidanS4 我有点担心我的例子的答案是“你不能真的那样做”。 =(

标签: c# dispose comobject


【解决方案1】:

这个真的属于汉斯·帕桑特,他偶然发现了原始问题的问题,但从未发布过实际答案。

lengthy answer to another question 中,他详细说明了为什么手动释放充其量只是一件傻事。他还详细介绍了为什么我们实际上会让这些幽灵实例四处游荡,以及如何摆脱它们。我真的鼓励任何有这个问题的人去阅读整篇文章(它的信息非常丰富),但如果你现在处于紧要关头并且需要,让我总结一下:

是的,就是这样。这里的所有都是它的。调试器有点烦人,似乎喜欢让垃圾收集器相信有些事情在实际上并不重要时仍然很重要。我知道,你不认为这是你的问题,你认为这是疯狂的。我也有同样的感觉,但试一试;很快就解决了我的问题。

再次感谢 Hans Passant,你这个坚忍的 C-Sharpian。

【讨论】:

  • 你得到了一半的答案。另一半是Tools + Options,Debugging,General,把“Suppress JIT optimization”选项去掉。现在它以在您的用户机器上运行的方式运行。顺便说一句,这很不寻常。
  • @HansPassant 是的,我看到了,但甚至不需要走那么远。不知何故,这对我来说效果非常好。不过,我会将其添加到答案中。再次感谢!
猜你喜欢
  • 2015-09-25
  • 2012-09-17
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-05
  • 2014-02-14
相关资源
最近更新 更多