2015-10-19 39 views
0

我需要檢查給定工作簿中是否存在具有某個特定名稱的工作表。在這個技巧中是否有任何缺陷通過調用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; 
    } 
} 

但是,例外的是煩人。在調試我的程序的其他不相關部分時,我一次又一次地浪費了我的時間。

我也想避免遍歷工作簿的每個工作表,比較名稱。這在我看來是非常低效的。

經過一番研究,我提出了這個解決方案,WHIS是基於評估()的事實,在失敗時拋出一個異常,而不是返回錯誤代碼:

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的建議迭代Sheets集合,當只有幾張紙(13 us,無論紙張是否存在)時,甚至需要更短的時間。但是這些時間隨着牀單數量的增加而增加。使用77頁,如果搜索到的頁面是最後一個或不存在的頁面,迭代大約需要200 us。但是,這是很多牀單!

回答

1

你能不能做這樣的事情:

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

正如我所說,迭代工作簿中的每個工作表在我看來效率低下。我在一本工作手冊中有幾十張紙。我沒有描述它,但這麼多的調用Interop ...不能很快 – comocomocomocomo

+0

我建議分析這兩個 - 對我來說,依靠'Evaluate()'似乎shakey至多。錯誤處理也不是免費的,也依賴像R1C1參考樣式問題的警告似乎有點可疑。如果你知道工作表的索引,它看起來像你:'workbook.Worksheets [1]'那麼你只需要得到該索引表並比較名稱......這是如何低效?在什麼情況下調用「ContainsSheet」? – DGibbs

+0

哦,我不知道索引。我得到工作表[1],因爲我需要一張表來調用Evaluate()。任何表都很好。而且,正如Excel本身所說的,當您嘗試刪除每個工作表時,「工作簿必須至少包含一個可見工作表。」 – comocomocomocomo

相關問題