[英]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.