[英]Is there any flaw in this trick to check whether a sheet exists by calling Evaluate?
I need to check whether a sheet with some specific name exists in a given workbook. 我需要检查给定工作簿中是否存在具有某些特定名称的工作表。
The naive way to do this is something like: 天真的方法是这样的:
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;
}
}
But that exception is annoying. 但是这种例外很烦人。 It is wasting my time once and again while debugging other unrelated parts of my program.
在调试程序的其他不相关部分时,这一次又一次地浪费了我的时间。
I also want to avoid iterating through every worksheet of the workbook, comparing names. 我还想避免在工作簿的每个工作表中都进行迭代,以比较名称。 That looks to me profoundly inefficient.
在我看来,这是非常低效的。
After some research, I made up this solution, whis is based on the fact that Evaluate() returns an error code when it fails instead of throwing an exception: 经过研究,我组成了这个解决方案,这是基于以下事实: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;
}
But this fails if the "R1C1 reference style" is activated in Excel (menu: Tools / Options / General). 但是,如果在Excel中激活了“ R1C1参考样式”,则此操作将失败(菜单:工具/选项/常规)。 Taking that into account...
考虑到这一点...
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;
}
I know I could check ReferenceStyle first and then call Evaluate() just once with the correct style. 我知道我可以先检查ReferenceStyle,然后使用正确的样式调用Evaluate()一次。 Something like:
就像是:
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;
Anyway, my question is: Is there any other flaw in my ContainsSheet() function? 无论如何,我的问题是: ContainsSheet()函数是否还有其他缺陷?
UPDATE : The method proposed here takes a very short time (about 30 us) when the sheet exists, but a long time when it does not exist (about 150 us). 更新 :当工作表存在时,此处提出的方法需要很短的时间(大约30 us),而当工作表不存在时,则需要很长时间(大约150 us)。 Evaluate() must be provoking and catching an exception internally.
Evaluate()必须在内部引发并捕获异常。 Instead, iterating through the Sheets collection, as proposed by DGibbs below, takes even shorter times when there are just a few sheets (13 us, no matter whether the sheet exists or not).
相反,如下面的DGibbs所建议的那样,在Sheets集合中进行迭代时,如果只有几张图纸(无论是否存在,则为13 us),花费的时间甚至更短。 But these timings grow with the number of sheets.
但是,这些时间随印张数量的增加而增加。 With 77 sheets, if the sheet searched is one of the last ones or does not exist, iterating takes about 200 us.
使用77张纸,如果搜索到的纸是最后一张纸或不存在,则迭代大约需要200 us。 However, that's a lot of sheets!
但是,床单很多!
Could you not do something like: 你能不能做这样的事情:
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;
}
Much simpler and is a handy extension method. 简单得多,并且是一种方便的扩展方法。
var hasSheet = workbook.ContainsSheet("foo");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.