这个技巧是否有任何缺陷通过调用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; } }
但是这个例外令人讨厌。 这是浪费我的时间一次又一次,而我的程序debugging其他无关的部分。
我也想避免遍历工作簿的每个工作表,比较名称。 这在我看来是非常低效的。
经过一番研究,我做出了这个解决scheme,whis是基于这样一个事实:Evaluate()在失败而不是抛出exception时返回一个错误代码:
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()必须在内部激发和捕捉exception。 相反,按照下面的DGibbs的build议迭代Sheets集合,当只有几张纸(13 us,无论纸张是否存在)时甚至需要更短的时间。 但是这些时间随着纸张的数量而增长。 有77页,如果search到的页面是最后一个或者不存在的页面,迭代大约需要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");