c# – 使用Wrapper对象来正确清理excel的互操作对象

所有这些问题:

> Excel 2007 Hangs When Closing via .NET
> How to properly clean up Excel interop objects in C#
> How to properly clean up interop objects in C#

C#在使用它们后不会正确释放Excel COM对象的问题.这个问题主要有两个方向:

>当Excel不再使用时,请关闭Excel进程.
>请注意,首先明确分配用于变量的每个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;
    }
}

我的问题特别是:

谁发现这是一个坏主意,为什么?
谁找到这个gread的想法?如果是这样,为什么还没有人实施/发布这样的模型?这只是由于努力,还是我错过了这个想法的杀人问题?
>在终结器中是否不可能/不好/容易出错的ReleaseCOMObject? (我只看过把它放在一个Dispose()而不是一个finalizer中的提议 – 为什么?)
>如果方法有意义,有什么建议来改进吗?

解决方法

Is it impossible/bad/dangerous to do the ReleaseCOMObject in the destructor? (I’ve only seen proposals to put it in a Dispose() rather than in a destructor – why?)

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

您链接的这个solution试图通过显式调用垃圾收集器并等待finalizer完成来解决这个问题.这一般不是一般推荐的,但是对于这种特定情况,有些人认为这是一个可以接受的解决方案,因为难以跟踪所有创建的临时非管理对象.但明确的清理是正确的方法.但是,由于这样做的困难,所以这个“黑客”可能是可以接受的.请注意,此解决方案可能优于您提出的想法.

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

相关文章

文章浏览阅读6.2k次,点赞2次,收藏3次。C#数学运算表达式解...
文章浏览阅读5.2k次,点赞6次,收藏7次。程序要做到用户配置...
文章浏览阅读9k次。错误信息检测到 ContextSwitchDeadlock M...
文章浏览阅读2w次,点赞10次,收藏9次。我发生错误时的环境:...
文章浏览阅读9.8k次。C# 二进制字节流查找函数IndexOf ...
文章浏览阅读2.5w次,点赞3次,收藏9次。c#DataGridView数据...