所有这些问题:
在使用完Excel COM对象后,C#无法正确释放它们,这是一个常见的问题。解决此问题主要有两个方向:
- 在不再使用Excel时杀死Excel进程。
- 确保显式地将每个使用的COM对象分配给一个变量,并保证最终在每个对象上执行Marshal.ReleaseComObject。
有人表示,方法2太繁琐了,在代码中可能会忘记遵循此规则,存在一定的不确定性。而方法1似乎又很不可靠,而且容易出错,特别是在受限制的环境中试图杀死进程可能会引发安全错误。
所以我正在思考通过创建另一个代理对象模型来解决方法2,该模型模拟Excel对象模型(对我来说,只实现我实际需要的对象即可)。其原理如下:
- 每个Excel互操作类都有其代理,它包装了该类的一个对象。
- 代理在其终结器中释放COM对象。
- 代理模拟互操作类的接口。
- 任何最初返回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;
}
}
我的问题具体是:
- 谁认为这是一个不好的想法,为什么?
- 谁认为这是一个伟大的想法?如果是这样,为什么还没有人实现/发布这样的模型?这只是由于工作量,还是我忽略了这个想法的致命问题?
- 在finalizer中使用ReleaseCOMObject是否不可能/错误/容易出错?(我只见过将其放在Dispose()而不是finalizer中的提案 - 为什么?)
- 如果这种方法是有意义的,有什么建议可以改进它吗?