【发布时间】:2012-02-08 00:03:40
【问题描述】:
我有这段代码用于从 excel 单元格中读取:
public T GetValue<T>(string testsheet, string range)
{
Application excelApplication = null;
Workbooks workBooks = null;
Workbook activeWorkBook = null;
Worksheet activeWorkSheet = null;
try
{
excelApplication = new Application();
workBooks = excelApplication.Workbooks;
activeWorkBook = workBooks.Open(workBook);
activeWorkSheet = activeWorkBook.ActiveSheet;
var cells = activeWorkSheet.get_Range(range);
return cells.Value2;
}
catch (Exception theError)
{
Console.WriteLine(theError.Message);
throw theError;
}
finally
{
ReleaseComObject(activeWorkSheet);
ReleaseComObject(activeWorkBook);
ReleaseComObject(workBooks);
ReleaseComObject(excelApplication);
}
}
我还有一个 Set value 方法,它将值设置为单元格,如下所示:
public void SetValue<T>(string testsheet, string range, T value)
{
Application excelApplication = null;
Workbooks workBooks = null;
Workbook activeWorkBook = null;
Worksheet activeWorkSheet = null;
try
{
excelApplication = new Application();
workBooks = excelApplication.Workbooks;
activeWorkBook = workBooks.Open(workBook);
activeWorkSheet = activeWorkBook.ActiveSheet;
var cells = activeWorkSheet.get_Range(range);
cells.Value2 = value;
activeWorkBook.Save();
}
catch (Exception theError)
{
Console.WriteLine(theError.Message);
throw theError;
}
finally
{
if (activeWorkBook != null)
activeWorkBook.Close();
ReleaseComObject(excelApplication);
ReleaseComObject(workBooks);
ReleaseComObject(activeWorkBook);
ReleaseComObject(activeWorkSheet);
}
}
这是我的 ReleaseComObject:
private static void ReleaseComObject<T>(T comObject) where T : class
{
if (comObject != null)
Marshal.ReleaseComObject(comObject);
}
我已经编写了一个测试,以确保 excel 对象按如下方式正确处理:
[Test]
public void Should_dispose_excel_objects_created_after_io_operation()
{
var expected = Process.GetProcesses().Count(process => process.ProcessName.ToLower() == "excel");
var automationClient = new ExcelAutomation.ExcelAutomationClient(ExcelSheet);
automationClient.SetValue("Sheet1", "A1", 1200);
automationClient.GetValue<double>("Sheet1", "A1");
var actual = Process.GetProcesses().Count(process => process.ProcessName.ToLower() == "excel");
actual.Should().Be(expected, "Excel workbook is not disposed properly. There are still excel processess in memory");
}
如果我只调用 SetValue 方法,则此测试通过,但是在调用 GetValue 时它会失败。但是我在任务管理器中看不到 Excel.exe。知道为什么会这样吗?我的 GetValue 函数有问题吗?
【问题讨论】:
-
我相信
get_Range返回一个COM 对象,所以你也应该释放它。虽然,您在两种方法中都调用它。 -
它与处置无关。您正在编写 C 代码,手动管理内存。随着不可避免的错误产生,“泄漏”内存。您没有为 cells 对象引用调用 ReleaseComObject()。只是不要写这样的代码,没有意义。垃圾收集器已经知道如何做到这一点。如果您出于某种原因想加快速度,请调用 GC.Collect()。只要你有充分的理由。
-
如果你比较这两种方法,我在做几乎相同的事情。如果我不调用 ReleaseComObject,则 excel 实例会在内存中徘徊。只有在调用它之后它才会消失。即使在这种情况下它也会消失,但测试没有通过。
-
使用杀死应用程序win32 API stackoverflow.com/questions/7956519/…
-
@HansPassant : 这就是您针对 Excel 编写代码的方式 :) support.microsoft.com/kb/317109