gpt4 book ai didi

c# - 是否需要使用 Marshal.ReleaseComObject 释放*每个* Excel 互操作对象?

转载 作者:IT王子 更新时间:2023-10-29 04:14:54 26 4
gpt4 key购买 nike

编辑

另请参阅 How do I properly clean up Excel interop objects? .我最近遇到了这个问题,它提供了很多关于如何正确处理 COM 对象的问题的见解。一定要检查第一个(标记的)答案,因为其他答案超出了简单的“不要使用两个点”和“对每个 com 对象使用 ReleaseComObject”的建议。

我首先重新审视了这个问题,因为我意识到,尽管我对所有 COM 对象的注册和处置都非常彻底,但我的 Excel 实例仍然没有得到正确处置。事实证明,有一些方法可以创建完全不明显的 COM 对象(即,即使您从不使用两个点,也可能会错过 COM 对象)。此外,即使你很彻底,如果你的项目增长超过一定规模,那么遗漏 COM 对象的可能性接近 100%。当发生这种情况时,很难找到您错过的那个。上面链接的问题的答案提供了一些其他技术来确保 Excel 实例确实关闭。同时,我对我的 ComObjectManager(如下)做了一个小的(但重要的)更新,以反射(reflect)我从上面链接的问题中学到的东西。

原始问题

我见过几个例子,其中 Marshal.ReleaseComObject() 与 Excel Interop 对象(即来自命名空间 Microsoft.Office.Interop.Excel 的对象)一起使用,但我见过它使用在不同程度上。

我想知道我是否可以摆脱这样的事情:

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

促使我问这个问题的是,作为 LINQ 的忠实拥护者,我真的很想做这样的事情:

var worksheetNames = worksheets.Cast<Worksheet>().Select(ws => ws.Name);

...但我担心如果我不释放每个工作表 (ws) 对象,我最终会遇到内存泄漏或幽灵进程。

如有任何见解,我们将不胜感激。

更新

根据目前的答案,听起来我确实需要释放我创建的每一个 com 对象。我借此机会构建了一个 ComObjectManager 类,以便更轻松地处理这个令人头疼的问题。每次实例化一个新的 com 对象时,您都必须记住使用 Get() 方法,但如果您这样做,它将为您处理其他所有事情。如果您发现任何问题,请告诉我(如果可以,请编辑并发表评论)。这是代码:

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

最佳答案

我相信您必须对每个 COM 对象调用 ReleaseComObject。由于它们未被垃圾回收,因此父子层次结构并未真正纳入等式:即使您释放父对象,它也不会减少任何子对象的引用计数。

关于c# - 是否需要使用 Marshal.ReleaseComObject 释放*每个* Excel 互操作对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2926205/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com