所有这些问题:
解决了C#在使用后没有正确释放Excel COM对象的问题。解决这个问题主要有两个方向:
有些人表示2太繁琐,而且在代码中的某些地方忘记遵守此规则总是存在一些不确定性。仍然1对我来说似乎很脏并且容易出错,我想在有限的环境中试图杀死进程可能会引发安全错误。
所以我一直在考虑通过创建另一个模仿Excel对象模型的代理对象模型来解决问题2(对我来说,实现我真正需要的对象就足够了)。原则如下:
示例:
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;
}
}
我特别向您提出的问题:
答案 0 :(得分:5)
在析构函数中执行ReleaseCOMObject是不可能/坏/危险的? (我只看到过将它放在Dispose()而不是析构函数中的建议 - 为什么?)
建议不要将清理代码放在终结器中,因为与C ++中的析构函数不同,它不是确定性调用的。在对象超出范围后不久可能会调用它。可能需要一个小时。它可能永远不会被调用。通常,如果要处置非托管对象,则应使用IDisposable模式而不是终结器。
您链接到的solution尝试通过显式调用垃圾收集器并等待终结器完成来解决该问题。实际上这并不是一般的推荐,但是对于这种特殊情况,有些人认为它是一种可接受的解决方案,因为很难跟踪所有创建的临时非托管对象。但明确清理是正确的方法。然而,考虑到这样做的困难,这种“黑客”可能是可以接受的。请注意,此解决方案可能比您提出的想法更好。
如果您想尝试明确清理,“不要在COM对象中使用两个点”指南将帮助您记住保留对您创建的每个对象的引用,以便您可以在清理时清除它们'完了。
答案 1 :(得分:2)
我们使用MSDN杂志中描述的LifetimeScope类。使用它可以正确清理对象,并且可以很好地处理Excel导出。代码可以在这里下载,也包含杂志文章:
http://lifetimescope.codeplex.com/SourceControl/changeset/changes/1266
答案 2 :(得分:1)
查看我的项目MS Office for .NET。通过本机VB.NET后期绑定能力解决了参考包装对象和本机对象的问题。
答案 3 :(得分:0)
我要做什么:
class ScopedCleanup<T> : IDisposable where T : class
{
readonly Action<T> cleanup;
public ScopedCleanup(T o, Action<T> cleanup)
{
this.Object = o;
this.cleanup = cleanup;
}
public T Object { get; private set; }
#region IDisposable Members
public void Dispose()
{
if (Object != null)
{
if(cleanup != null)
cleanup(Object);
Object = null;
GC.SuppressFinalize(this);
}
}
#endregion
~ScopedCleanup() { Dispose(); }
}
static ScopedCleanup<T> CleanupObject<T>(T o, Action<T> cleanup) where T : class
{
return new ScopedCleanup<T>(o, cleanup);
}
static ScopedCleanup<ComType> CleanupComObject<ComType>(ComType comObject, Action<ComType> actionBeforeRelease) where ComType : class
{
return
CleanupObject(
comObject,
o =>
{
if(actionBeforeRelease != null)
actionBeforeRelease(o);
Marshal.ReleaseComObject(o);
}
);
}
static ScopedCleanup<ComType> CleanupComObject<ComType>(ComType comObject) where ComType : class
{
return CleanupComObject(comObject, null);
}
用法案例。注意调用Quit,这似乎是使进程结束所必需的:
using (var excel = CleanupComObject(new Excel.Application(), o => o.Quit()))
using (var workbooks = CleanupComObject(excel.Object.Workbooks))
{
...
}
答案 4 :(得分:0)
对于它的价值,Excel Refresh Service on codeplex使用了这个逻辑:
public static void UsingCOM<T>(T reference, Action<T> doThis) where T : class
{
if (reference == null) return;
try
{
doThis(reference);
}
finally
{
Marshal.ReleaseComObject(reference);
}
}