使用Wrapper对象来正确清理excel的互操作对象 [英] Using Wrapper objects to Properly clean up excel interop objects

查看:120
本文介绍了使用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对象的问题。这个问题主要有两个方向:

struggle with the problem that C# does not release the Excel COM objects properly after using them. There are mainly two directions of working around this issue:


  1. 当Excel不再被使用时,可以关闭Excel进程。

  2. 请小心明确地分配给变量使用的每个COM对象,并确保最终每个执行Marshal.ReleaseComObject。

有些人表示,2太乏味,总是有一些不确定性,无论你是否在代码中的某些地方忘记遵守这一规则。仍然1似乎很脏,容易出错,我也猜测在一个有限的环境下试图杀死一个进程可能会引发安全错误。

Some have stated that 2 is too tedious and there is always some uncertainty whether you forget to stick to this rule at some places in the code. Still 1 seems dirty and error-prone to me, also I guess that in a restricted environment trying to kill a process could raise a security error.

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

So I've been thinking about solving 2 by creating another proxy object model which mimics the Excel object model (for me, it would suffice to implement the objects I actually need). The principle would look as follows:


  • 每个Excel Interop类都有它的代理,它包装该类的对象。

  • 代理在其终结器中释放COM对象。

  • 代理模拟Interop类的界面。

  • 最初返回一个COM对象被改为返回一个代理。其他方法简单地将实现委托给内部COM对象。

  • Each Excel Interop class has its proxy which wraps an object of that class.
  • The proxy releases the COM object in its finalizer.
  • The proxy mimics the interface of the Interop class.
  • Any methods that originally returned a COM object are changed to return a proxy instead. The other methods simply delegate the implementation to the inner COM object.

示例:

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中的提议 - 为什么?)

  • 如果这个方法有意义,有什么建议来改进它? >
  • Who finds this a bad idea and why?
  • Who finds this a gread idea? If so, why hasn't anybody implemented/published such a model yet? Is it only due to the effort, or am I missing a killing problem with that idea?
  • Is it impossible/bad/error-prone to do the ReleaseCOMObject in the finalizer? (I've only seen proposals to put it in a Dispose() rather than in a finalizer - why?)
  • If the approach makes sense, any suggestions to improve it?

推荐答案


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

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模式,而不是finalizer。

It is recommended not to put your clean up code in the finalizer because unlike the destructor in C++ it is not called deterministically. It might be called shortly after the object goes out of scope. It might take an hour. It might never be called. In general if you want to dispose unmanaged objects you should use the IDisposable pattern and not the finalizer.

这个解决方案,您链接到试图解决这个问题,明确地调用垃圾收集器并等待终结者完成。这一般不是一般推荐的,但对于这种特殊情况,有些人认为这是一个可以接受的解决方案,因为难以跟踪所有创建的临时非管理对象。但明确的清理是正确的方法。但是,由于这样做的困难,所以这个黑客可能是可以接受的。请注意,该解决方案可能比您提出的想法更好。

This solution that you linked to attempts to work around that problem by explicitly calling the garbage collector and waiting for the finalizers to complete. This is really not recommended in general but for this particular situation some people consider it to be an acceptable solution due to the difficulty of keeping track of all the temporary unmanaged objects that get created. But explicitly cleaning up is the proper way of doing it. However given the difficulty of doing so, this "hack" may be acceptable. Note that this solution is probably better than the idea you proposed.

如果您想要尝试显式清理,不要使用COM对象的两个点指南将帮助您记住保留对每个您创建的对象的引用,以便在完成后将其清理。

If instead you want to try to explicitly clean up, the "don't use two dots with COM objects" guideline will help you to remember to keep a reference to every object you create so that you can clean them up when you're done.

这篇关于使用Wrapper对象来正确清理excel的互操作对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆