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

查看:230
本文介绍了使用包装对象要正确清理Excel的互操作对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所有这些问题:





与C#不释放Excel的COM使用后有正当理由反对这一问题的斗争。主要有解决这个问题的工作的两个方向:




  1. 杀死当Excel不再使用Excel进程

  2. 小心明确指定用于可变第一,每个COM对象,以保证最终,Marshal.ReleaseComObject的是在每个执行。



有人说,2过于繁琐,总有一些不确定性是否忘了坚持这个规则在代码中的一些地方。还是1看起来脏且容易出错给我,我也想在受限环境中试图杀死一个进程可能引发安全错误。



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




  • 每个Excel的互操作类都有其代理它包装类的一个对象

  • 代理释放COM对象在它的终结。

  • 代理模仿互操作类的接口。

  • 所有的方法原本返回COM对象改变返回一个代理来代替。其他方法只是委托实施内部COM对象



例如:

 公共类应用
{
私人Microsoft.Office.Interop.Excel.Application innerApplication
=新Microsoft.Office.Interop.Excel.Application innerApplication();

〜应用程序()
{
对Marshal.ReleaseComObject(innerApplication);
innerApplication = NULL;
}

公开工作簿簿
{
{返回新的工作簿(innerApplication.Workbooks); }
}
}

公共类的工作簿
{
私人Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks;

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

〜工作簿()
{
对Marshal.ReleaseComObject(innerWorkbooks);
innerWorkbooks = NULL;
}
}

我的问题,你有具体为:




  • 谁认为这是一个坏主意,为什么?

  • 谁认为这一个gread想法?如果是这样,为什么没有任何人实行/发表这样的模式吗?它仅仅是由于努力,还是我失去了与这个想法杀人的问题?

  • 是不可能/坏/易出错做ReleaseComObject的的终结? (我只看到提案,把它放在一个Dispose()方法,而不是终结 - 为什么)?

  • 如果该方法是有道理的,任何建议,以改善它


解决方案

它是不可能的/坏/危险做ReleaseComObject的中析构函数? (我只看到提案,把它放在一个Dispose()方法,而不是在析构函数 - 为什么)




建议不要把在终结你的清理代码,因为不像在C ++中它不叫做确定性的析构函数。它可能在短期内调用的对象超出范围后。这可能需要一个小时。它可能永远不会被调用。一般来说,如果你要处理,你应该使用IDisposable模式,而不是终结非托管对象。



这的解决方案你通过显式调用垃圾回收器,然后等待挂试图解决这个问题在终结来完成。这实在不是一般的建议但对于这种特殊情况下有些人认为这是一个可以接受的解决方案,因为跟踪所有获得创建的临时非托管对象的难度。但明确的清理是这样做的正确方法。然而鉴于这样做的困难,这个黑客是可以接受的。请注意,这种解决方案可能比你提出的想法更好。



如果不是你想尝试显式清理,不使用两个点与COM对象指南将帮助您要记得保持对它的引用每个对象创建,这样就可以清除它们时,你就大功告成了。


All of these questions:

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. Kill the Excel process when Excel is not used anymore.
  2. Take care to explicitly assign each COM object used to a variable first and to guarantee that eventually, Marshal.ReleaseComObject is executed on each.

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.

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:

  • 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.

Example:

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;
    }
}

My questions to you are in particular:

  • 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?

解决方案

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?)

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.

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.

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

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