使用Wrapper对象正确清理excel互操作对象

chi*_*oro 11 c# excel interop com-interop

所有这些问题:

解决了C#在使用后没有正确释放Excel COM对象的问题.解决这个问题主要有两个方向:

  1. 不再使用Excel时终止Excel进程.
  2. 注意首先明确地将用于变量的每个COM对象分配,并保证最终在每个上执行Marshal.ReleaseComObject.

有人说过2太繁琐了,你是否忘记在代码中的某些地方忘记遵守这条规则总是存在一些不确定性.仍然1对我来说似乎很脏并且容易出错,我想在有限的环境中试图杀死一个进程可能会引发安全错误.

所以我一直在考虑通过创建另一个模仿Excel对象模型的代理对象模型来解决问题2(对我来说,实现我实际需要的对象就足够了).原则如下:

  • 每个Excel Interop类都有其代理,用于包装该类的对象.
  • 代理在其终结器中释放COM对象.
  • 代理模仿Interop类的接口.
  • 最初返回COM对象的任何方法都会更改为返回代理.其他方法只是将实现委托给内部COM对象.

例:

public class Application
{
    private Microsoft.Office.Interop.Excel.Application innerApplication
        = new Microsoft.Office.Interop.Excel.Application innerApplication();

    ~Application()
    {
        Marshal.ReleaseCOMObject(innerApplication);
        innerApplication = null;
    }

    public Workbooks Workbooks
    {
        get { return new Workbooks(innerApplication.Workbooks); }
    }
}

public class Workbooks
{
    private Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks;

    Workbooks(Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks)
    {
        this.innerWorkbooks = innerWorkbooks;
    }

    ~Workbooks()
    {
        Marshal.ReleaseCOMObject(innerWorkbooks);
        innerWorkbooks = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我特别向你提问:

  • 谁发现这是一个坏主意,为什么?
  • 谁发现这是一个可怕的想法?如果是这样,为什么没有人实施/发布这样的模型呢?是仅仅是因为努力,还是我错过了这个想法的杀戮问题?
  • 在终结器中执行ReleaseCOMObject是不可能/不好/容易出错的吗?(我只看到过将它放在Dispose()而不是终结器中的建议 - 为什么?)
  • 如果方法有意义,有什么建议可以改进吗?

Mar*_*ers 5

在析构函数中执行ReleaseCOMObject是不可能/不好/危险的吗?(我只看到过将它放在Dispose()而不是析构函数中的建议 - 为什么?)

建议不要将清理代码放在终结器中,因为与C++中的析构函数不同,它不是确定性的.在对象超出范围后不久可能会调用它.可能需要一个小时.它可能永远不会被调用.通常,如果要处置非托管对象,则应使用IDisposable模式而不是终结器.

您链接的此解决方案通过显式调用垃圾收集器并等待终结器完成来尝试解决该问题.实际上不建议这样做,但是对于这种特殊情况,有些人认为这是一个可接受的解决方案,因为很难跟踪所有创建的临时非托管对象.但明确清理是正确的方法.然而,考虑到这样做的困难,这种"黑客"可能是可以接受的.请注意,此解决方案可能比您提出的想法更好.

如果您想尝试明确清理,"不要使用带有COM对象的两个点"指南将帮助您记住保留对您创建的每个对象的引用,以便您可以在完成后清理它们.