所以我有一个 Winforms 应用程序,它需要从 Excel 工作表中读取以填充一些字段。为了使 UI 响应,我决定创建一个线程来读取 Excel 工作表,这样主线程就不必等待。如果读取完成,然后应用程序退出,EXCEL.EXE 表现良好并退出。但是,如果我在读取仍在进行时关闭主应用程序,则 EXCEL.EXE 任务将保持活动状态。
我猜那是因为在它关闭之前ExcelReader
没有时间打电话?destructor
一种可能的解决方案是ExcelReader.Cleanup
在它的FormClosing
事件中调用主表单。但这似乎是对封装的可怕违反。
对此还有哪些其他可能的解决方案?这是我的 ExcelReader 代码:
using Excel = Microsoft.Office.Interop.Excel;
class ExcelReader
{
private int sheetNum { get ; set; }
public int rowCount { get; private set; }
public int colCount { get; private set; }
public List<string> sheetValues { get; private set; }
public List<string> sheetNames { get; private set; }
Excel.Application xlApp;
Excel.Workbooks workBooks;
Excel.Workbook xlWorkbook;
Excel.Worksheet xlWorkSheet;
Excel.Range xlRange;
Excel.Range row;
Excel.Range col;
public ExcelReader(string path){
//initialize values
this.sheetNum = 1;
sheetNames = new List<string>();
sheetValues = new List<string>();
//read from excel blackmagic here
xlApp = new Excel.Application();
workBooks = xlApp.Workbooks;
xlWorkbook = workBooks.Open(path);
xlWorkSheet = xlWorkbook.Sheets[sheetNum];
xlRange = xlWorkSheet.UsedRange;
row = xlRange.Rows;
col = xlRange.Columns;
int rowCount = row.Count;
int colCount = col.Count;
this.getSheetNames(xlWorkbook);
this.getValues(xlRange, rowCount, colCount);
CleanUp();
}
~ExcelReader()
{
CleanUp();
}
private void getSheetNames(Excel.Workbook xlWorkbook)
{
var workSheets = xlWorkbook.Sheets;
int numberOfSheets = workSheets.Count;
for (int i = 1; i < numberOfSheets+1; i++)
{
sheetNames.Add(xlWorkbook.Sheets[i].Name);
}
Marshal.FinalReleaseComObject(workSheets);
}
private void getValues(Excel.Range xlRange, int rowCount, int colCount)
{
for (int i = 1; i < rowCount; i++)
{
for (int j = 1; j < colCount; j++)
{
var cells = xlRange.Cells[i, j];
var value = cells.Value2;
sheetValues.Add(value);
Marshal.FinalReleaseComObject(cells);
}
}
}
private void CleanUp()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
col.Clear();
row.Clear();
Marshal.FinalReleaseComObject(col);
Marshal.FinalReleaseComObject(row);
xlRange.Clear();
Marshal.FinalReleaseComObject(xlRange);
//close book without saving
xlWorkbook.Close(false);
workBooks.Close();
Marshal.FinalReleaseComObject(xlWorkbook);
Marshal.FinalReleaseComObject(workBooks);
xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);
}
}