1

我在发布 Excel Interop Com Objects 时遇到问题,当我尝试保存然后关闭通过 Excel Interop 创建的 Excel 工作簿时,这会导致我的 c# 应用程序崩溃。我觉得问题在于,在某些情况下,我将“2 点”与 excel 互操作 COM 对象一起使用,而我所阅读的内容是不允许的。我已经从大多数代码行中消除了 2 个点,但我一直在想办法重新创建以下代码行,以便它们只使用一个点。如果有人有任何建议,我将不胜感激。

workbook = (Excel.Workbook)app.Workbooks.Open(startForm.excelFileLocation,);

workbook = (Excel.Workbook)app.Workbooks.Add(1);

workSheet_range.Font.Color = System.Drawing.Color.FloralWhite.ToArgb();

workSheet_range.Font.Bold = font;

workSheet_range.Interior.Color = System.Drawing.Color.Red.ToArgb();
4

3 回答 3

3

验证每条指令的返回类型并分别分解。

您的第一行以“app.Workbooks”开头,它返回一个 Workbooks 类型的对象。然后 Open 指令返回一个 Workbook:

workbooks = app.Workbooks;
workbook = workbooks.Open(startForm.excelFileLocation);

然后,您可以像这样拆分第二个:

workbook = workbooks.add(1);

如果您没有“点缀”实际的 InterOp 对象,则可以使用多个点。

这是一个完整的示例:

Using Excel = Microsoft.Office.Interop.Excel;
public void Read()
{
    Excel.Application xlApp = new Excel.Application();
    Excel.Workbooks xlWorkBooks = xlApp.Workbooks;
    Excel.Workbook xlWorkBook = xlWorkBooks.Open(sourceFile);
    Excel.Worksheet xlWorkSheet = xlWorkBook.Worksheets[ 1 ];

    Excel.Range range = xlWorkSheet.UsedRange;
    range = range.Cells;
    Array myValues = ( Array )range.Value;    //now holds all the data in the sheet

    //The following is to ensure the EXCEL.EXE instance is released...
    //If you edit this code, know that using 2 dots (ex: range.Cells.Value) can create weird stuff!
    xlWorkBook.Close(false);
    xlWorkBooks.Close();
    xlApp.Quit();

    releaseObject(xlWorkSheet);
    releaseObject(xlWorkBook);
    releaseObject(xlWorkBooks);
    releaseObject(xlApp);

    xlWorkSheet = null;
    xlWorkBooks = null;
    xlWorkBook = null;
    xlApp = null;
}

private static void releaseObject( object obj )
{
try
{
    System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    obj = null;
}
catch (Exception ex)
{
    obj = null;
    Console.WriteLine("Unable to release the Object " + ex.ToString());
}
}
于 2012-10-25T13:10:53.447 回答
1

在这里总结所有信息。

  1. 分配时不要使用两个点。
  2. 使用AutoReleaseComObject类。
  3. 使用 Microsoft KB 中描述的 ReleaseObject 方法(使用 while 循环):Office 应用程序在从 .NET 客户端自动化后不会退出
  4. 使用 GC.Collect 和 GC.WaitForPendingFinalizers。
  5. 如果 Excel 进程在调试时保持活动状态,请不要感到惊讶,请始终通过运行应用程序来测试进程是否保持活动状态。

例如:

using Microsoft.Office.Interop.Excel;
...
var missing = Type.Missing;
using (AutoReleaseComObject<Microsoft.Office.Interop.Excel.Application> excelApplicationWrapper = new AutoReleaseComObject<Microsoft.Office.Interop.Excel.Application>(new Microsoft.Office.Interop.Excel.Application()))
{
    var excelApplicationWrapperComObject = excelApplicationWrapper.ComObject;
    excelApplicationWrapperComObject.Visible = true;

    var excelApplicationWrapperComObjectWkBooks = excelApplicationWrapperComObject.Workbooks;
    try
    {
        using (AutoReleaseComObject<Workbook> workbookWrapper = new AutoReleaseComObject<Workbook>(excelApplicationWrapperComObjectWkBooks.Open(@"C:\Temp\ExcelMoveChart.xlsx", false, false, missing, missing, missing, true, missing, missing, true, missing, missing, missing, missing, missing)))
        {
            var workbookComObject = workbookWrapper.ComObject;
            Worksheet sheetSource = workbookComObject.Sheets["Sheet1"];
            ChartObject chartObj = (ChartObject)sheetSource.ChartObjects("Chart 3");
            Chart chart = chartObj.Chart;
            chart.Location(XlChartLocation.xlLocationAsObject, "Sheet2");

            ReleaseObject(chart);
            ReleaseObject(chartObj);
            ReleaseObject(sheetSource);

            workbookComObject.Close(false);
        }
    }
    finally
    {
        excelApplicationWrapperComObjectWkBooks.Close();
        ReleaseObject(excelApplicationWrapperComObjectWkBooks);

        excelApplicationWrapper.ComObject.Application.Quit();
        excelApplicationWrapper.ComObject.Quit();
        ReleaseObject(excelApplicationWrapper.ComObject.Application);
        ReleaseObject(excelApplicationWrapper.ComObject);

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();    
    }
}

private static void ReleaseObject(object obj)
{
    try
    {
        while (System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        Console.WriteLine("Unable to release the Object " + ex.ToString());
    }
}

我知道释放所有对象,使用 GC.Collect 并且在分配时不使用两个点似乎在顶部,但至少当我退出 Excel 实例时,进程被释放,我不必以编程方式终止 Excel 进程!

于 2015-12-03T01:56:02.480 回答
-1

使用两个点并不是“不允许的”,但它肯定会对性能产生影响,尤其是在紧密循环中运行时。

每个“点”都是对 Excel 库的 COM 调用,它可能比正常的 CLR 对象访问慢得多。通常,您希望将 COM 调用的数量减少到尽可能少。

除非您重用相同的变量,否则通过分成两行将两个点减少到一个不会产生任何影响。例如,改变

workSheet_range.Interior.Color = System.Drawing.Color.Red.ToArgb();

var interior = workSheet_range.Interior;
interior.Color = System.Drawing.Color.Red.ToArgb();

将对性能产生interior影响,如果您不重新使用变量,甚至可能会“优化”回原始单行。

然而,改变

var font = workSheet_range.Font;
font.Color = System.Drawing.Color.FloralWhite.ToArgb();
font.Bold = font;

将减少一次调用,workSheet_range.Font因此您会看到增量收益。

底线

我不会太担心更改每个两点调用,而是使用一个好的分析工具来确定您的代码在哪里花费的时间最多,然后首先解决该区域。

于 2012-10-25T13:31:43.507 回答