编辑
How do I properly clean up Excel interop objects?
. 我最近遇到了这个问题,它为如何正确处理COM对象提供了很多见解。一定要在第一个(标记的)答案之外进行检查,因为其他答案超出了简单的“不要使用两点”和“使用两点”
ReleaseComObject
对于每个com对象”的建议。
我重新讨论了这个问题,因为我意识到,尽管我对注册和处理所有COM对象都非常仔细,但我的Excel实例仍然没有得到正确的处理。事实证明,有一些方法可以创建完全不明显的COM对象(即,即使从不使用两点,也可能丢失COM对象)。另外,即使你很彻底,如果你的项目超过了一定的规模,丢失一个COM对象的几率也接近100%。当这种情况发生时,很难找到你错过的那个。上面链接的问题的答案提供了一些其他技术来确保Excel实例被关闭。同时,我对我的网站做了一个小的(但意义重大的)更新
ComObjectManager
(以下)来反映我从上述问题中学到的东西。
我见过几个例子
Marshal.ReleaseComObject()
我想知道我是否能逃脱这样的惩罚:
var application = new ApplicationClass();
try
{
// do work with application, workbooks, worksheets, cells, etc.
}
finally
{
Marashal.ReleaseComObject(application)
}
或者如果我需要释放所创建的每个对象,如以下方法:
public void CreateExcelWorkbookWithSingleSheet()
{
var application = new ApplicationClass();
var workbook = application.Workbooks.Add(_missing);
var worksheets = workbook.Worksheets;
for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++)
{
var worksheet = (WorksheetClass)worksheets[worksheetIndex];
worksheet.Delete();
Marshal.ReleaseComObject(worksheet);
}
workbook.SaveAs(
WorkbookPath, _missing, _missing, _missing, _missing, _missing,
XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing);
workbook.Close(true, _missing, _missing);
application.Quit();
Marshal.ReleaseComObject(worksheets);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(application);
}
促使我问这个问题的原因是,作为林客的奉献者,我真的很想做这样的事情:
var worksheetNames = worksheets.Cast<Worksheet>().Select(ws => ws.Name);
…但我担心如果我不发布每个工作表,最终会导致内存泄漏或重影进程(
ws
对此有任何见解都将不胜感激。
更新
根据目前的答案,听起来我真的需要释放我创建的每个com对象。我利用这个机会建立了一个
上课,让你更容易对付这种头痛。你必须记住使用
Get()
方法每次实例化一个新的com对象时,但如果这样做,它将为您处理其他所有事情。请让我知道,如果你看到任何问题与它(或编辑,并留下评论,如果你能)。代码如下:
public class ComObjectManager : IDisposable
{
private Stack<object> _comObjects = new Stack<object>();
public TComObject Get<TComObject>(Func<TComObject> getter)
{
var comObject = getter();
_comObjects.Push(comObject);
return comObject;
}
public void Dispose()
{
// these two lines of code will dispose of any unreferenced COM objects
GC.Collect();
GC.WaitForPendingFinalizers();
while (_comObjects.Count > 0)
Marshal.ReleaseComObject(_comObjects.Pop());
}
}
下面是一个用法示例:
public void CreateExcelWorkbookWithSingleSheet()
{
using (var com = new ComObjectManager())
{
var application = com.Get<ApplicationClass>(() => new ApplicationClass());
var workbook = com.Get<Workbook>(() => application.Workbooks.Add(_missing));
var worksheets = com.Get<Sheets>(() => workbook.Worksheets);
for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++)
{
var worksheet = com.Get<WorksheetClass>(() => (WorksheetClass)worksheets[worksheetIndex]);
worksheet.Delete();
}
workbook.SaveAs(
WorkbookPath, _missing, _missing, _missing, _missing, _missing,
XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing);
workbook.Close(true, _missing, _missing);
application.Quit();
}
}