通过调用Evaluate来检查工作表是否存在的技巧是否存在缺陷

本文关键字:存在 是否 缺陷 工作 调用 Evaluate 检查 | 更新日期: 2023-09-27 18:18:14

我需要检查给定的工作簿中是否存在具有某些特定名称的工作表

简单的方法是:

using Excel = Microsoft.Office.Interop.Excel;
bool ContainsSheet (Excel.Workbook workbook, string sheetName)
{
    try
    {
        Excel.Worksheet sheet = workbook.get_Item(sheetName)
                                as Excel.Worksheet;
        return sheet != null;
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
        return false;
    }
}

但是那个例外很烦人。它一次又一次地浪费了我调试程序中其他不相关部分的时间。

我还想避免遍历工作簿的每个工作表,比较名称。在我看来,这种做法效率极低。

经过一番研究,我想出了这个解决方案,它是基于Evaluate()在失败时返回错误代码而不是抛出异常的事实:

using Excel = Microsoft.Office.Interop.Excel;
bool ContainsSheet (Excel.Workbook workbook, string sheetName)
{
    // Sadly, I need a sheet to call Evaluate
    Excel.Worksheet someSheet = workbook.Worksheets[1]
                                as Excel.Worksheet;
    if (someSheet == null)   // Is this even possible?
        return false;
    // Try to get a range referring the first cell (upper-left corner). Note that
    // Evaluate() returns a number if an error occurs...
    Excel.Range someRange = someSheet.Evaluate("''"+sheetName+"''!A1")
                            as Excel.Range;
    return someRange != null;
}

但是如果在Excel(菜单:工具/选项/常规)中激活"R1C1参考样式",则会失败。考虑到这一点……

using Excel = Microsoft.Office.Interop.Excel;
bool ContainsSheet (Excel.Workbook workbook, string sheetName)
{
    // Sadly, I need a sheet to call Evaluate
    Excel.Worksheet someSheet = workbook.Worksheets[1]
                                as Excel.Worksheet;
    if (someSheet == null)   // Is this even possible?
        return false;
    // Try to get a range referring the first cell (upper-left corner). Note that
    // Evaluate() returns a number if an error occurs...
    Excel.Range someRange = someSheet.Evaluate("''"+sheetName+"''!A1")
                            as Excel.Range;
    if (someRange != null)
        return true;
    // Try again with the alternative "R1C1 reference style", which can be activated
    // in the menu: Tools / Options / General
    someRange = someSheet.Evaluate("''"+sheetName+"''!R1C1")
                as Excel.Range;
    return someRange != null;
}

我知道我可以先检查ReferenceStyle,然后用正确的样式调用Evaluate()一次。比如:

Excel.Application excel = ExcelDna.Integration.ExcelDnaUtil.Application as Excel.Application;
System.Nullable<Excel.XlReferenceStyle> style = excel.ReferenceStyle as System.Nullable<Excel.XlReferenceStyle>;
string corner = style == null                          ? null :
                style == Excel.XlReferenceStyle.xlA1   ? "A1" :
                style == Excel.XlReferenceStyle.xlR1C1 ? "R1C1" : null;

无论如何,我的问题是:是否有任何其他缺陷在我的ContainsSheet()函数?

UPDATE:此处提出的方法在表单存在时花费的时间很短(约30 us),但在表单不存在时花费的时间很长(约150 us)。Evaluate()必须在内部触发并捕获异常。相反,正如下面DGibbs所建议的那样,当只有几个表(13个,不管表是否存在)时,迭代遍历Sheets集合所需的时间甚至更短。但这些时间随着纸张数量的增加而增加。对于77个表,如果搜索的表是最后一个表或不存在,迭代大约需要200个操作。然而,那是很多床单!

通过调用Evaluate来检查工作表是否存在的技巧是否存在缺陷

你能不能这样做:

public static bool ContainsSheet(this Excel.Workbook workbook, string sheetName)
{
     if(workbook.Sheets == null || !workbook.Sheets.Any())
           return false;
     foreach (var sheet in workbook.Sheets)
     {
          if (sheet.Name.Equals(sheetName))
          {
               return true;
          }
     }
     return false;
}

更简单,是一个方便的扩展方法。

var hasSheet = workbook.ContainsSheet("foo");