我有一个使用 COM Interop 连接到 Microsoft Office 应用程序的 WinForms 应用程序。我已经阅读了大量有关如何正确处理 COM 对象的材料,这是我的应用程序中使用 Microsoft 自己的文章(此处)中的技术的典型代码:
Excel.Application excel = new Excel.Application();
Excel.Workbook book = excel.Workbooks.Add();
Excel.Range range = null;
foreach (Excel.Worksheet sheet in book.Sheets)
{
range = sheet.Range["A2:Z2"];
// Process [range] here.
range.MergeCells();
System.Runtime.InteropServices.Marshal.ReleaseComObject(range);
range = null;
}
// Release explicitly declared objects in hierarchical order.
System.Runtime.InteropServices.Marshal.ReleaseComObject(book);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
book = null;
excel = null;
// As taken from:
// http://msdn.microsoft.com/en-us/library/aa679807(v=office.11).aspx.
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
所有异常处理都已被剥离,以使该问题的代码更清晰。
循环中的[sheet]
对象会发生什么?[foreach]
据推测,它不会被清理,我们也不能在它被枚举的时候对其进行篡改。一种替代方法是使用索引循环,但这会产生丑陋的代码,并且 Office 对象库中的某些结构甚至不支持索引。
此外,[foreach]
循环引用了 collection [book.Sheets]
。这是否也留下了孤立的 RCW 计数?
所以这里有两个问题:
- 需要枚举时最好的清理方法是什么?
[Sheets]
像in这样的中间对象[book.Sheets]
没有显式声明或清理,它们会发生什么?
更新:
我对 Hans Passant 的建议感到惊讶,并认为有必要提供一些背景信息。
这是客户端/服务器应用程序,客户端连接到许多不同的 Office 应用程序,包括 Access、Excel、Outlook、PowerPoint 和 Word 等。它有超过 1,500 个类(并且还在增加),用于测试最终用户正在执行的某些任务,并在培训模式下模拟它们。它用于培训和测试学生在学术环境中的 Office 熟练程度。由于有多个开发人员和大量的类,因此很难实施对 COM 友好的编码实践。我最终求助于结合使用反射和源代码解析来创建自动化测试,以确保这些类在代码前审查阶段的完整性。
会尝试一下 Hans 的建议并回复。