繁体   English   中英

通过调用“评估”检查工作表是否存在,此技巧是否存在任何缺陷?

[英]Is there any flaw in this trick to check whether a sheet exists by calling Evaluate?

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

天真的方法是这样的:

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()函数是否还有其他缺陷?

更新 :当工作表存在时,此处提出的方法需要很短的时间(大约30 us),而当工作表不存在时,则需要很长时间(大约150 us)。 Evaluate()必须在内部引发并捕获异常。 相反,如下面的DGibbs所建议的那样,在Sheets集合中进行迭代时,如果只有几张图纸(无论是否存在,则为13 us),花费的时间甚至更短。 但是,这些时间随印张数量的增加而增加。 使用77张纸,如果搜索到的纸是最后一张纸或不存在,则迭代大约需要200 us。 但是,床单很多!

你能不能做这样的事情:

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");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM