如何在C#中判断单元格的公式是否存在错误

26

在Excel公式中,您可以使用=ISERR(A1)=ISERROR(A1)

在VBA宏中,您可以使用IsError(sheet.Cells(1, 1))

但是,在使用VSTO Excel Addin项目时,我没有在Microsoft.Office.Interop.Excel API下找到类似的函数。我只想知道单元格中是否存在错误,不太关心错误的类型。

我的当前解决方法是针对所有现有的错误消息执行以下操作:

if (((Range)sheet.Cells[1, 1]).Text == "#N/A" || ...)

有更好的方法吗?API 中有一个简单的函数可以做到这一点吗?


(sheet.Cells[1,1] as Range).Text 看起来更好。 - Pratik Deoghare
看起来代码更好了,但如果某种原因下Cells[1,1]不是Range类型,则我们将会得到一个NullReferenceException而不是InvalidCastException。在这种情况下,我更倾向于获取更精确的异常类型而不是提高可读性。 - Pascal
2个回答

76

在.NET中处理CVErr值是一个非常棘手的问题。问题在于,就错误处理而言,.NET(正确地)认为CVErr已经过时了。然而,在Excel单元格中仍在使用CVErr值,因此这是Excel自动化的一个相当大的遗漏。

幸运的是,有一种解决方法。检查CVErr值的方法是检查单元格所持有的数据类型。如果持有的值被定义为Integer(Int32),则其所持有的值就是CVErr。(请注意,单元格中保存的数值通常被定义为Double,只有CVerr值可以作为整数传递。)

也就是说,在最简单的层面上,要测试CVErr值,你所需要做的就是使用以下函数:

bool IsXLCVErr(object obj)
{
    return obj is Int32;
}

如果您需要检查特定的 CVErr 值(例如 #N/A),那么您首先需要检查数据类型是否为 Integer(Int32),然后根据此表格检查单元格持有的特定值:

  • -2146826281 = #DIV/0!
  • -2146826246 = #N/A
  • -2146826245 = #GETTING_DATA
  • -2146826259 = #NAME?
  • -2146826288 = #NULL!
  • -2146826252 = #NUM!
  • -2146826265 = #REF!
  • -2146826273 = #VALUE!

例如,您的代码可能如下所示:

enum CVErrEnum : Int32
{
    ErrDiv0 = -2146826281,
    ErrGettingData = -2146826245,
    ErrNA = -2146826246,
    ErrName = -2146826259,
    ErrNull = -2146826288,
    ErrNum = -2146826252,
    ErrRef = -2146826265,
    ErrValue = -2146826273
}

bool IsXLCVErr(object obj)
{
    return (obj) is Int32;
}

bool IsXLCVErr(object obj, CVErrEnum whichError)
{
    return (obj is Int32) && ((Int32)obj == (Int32)whichError);
}

我几年前写了一篇详细的两部分文章:

这些文章是针对VB.NET编写的,但原理与C#完全相同。


13
这种回答让人们希望SO有一个“每天一次的超级赞”功能。 - AakashM
谢谢 Mike,这就是我整天在寻找的信息。我得到了一些奇怪的行数返回,没有意识到 VBA 将带有 CVErr 的单元格与 .net 处理方式不同(后者将其视为 Int 值)。 - Anonymous Type
最后,我认为code4life提供的解决方案正是我所寻找的。无论如何,感谢你提供的所有有关这个主题的好信息。 - Pascal
好的,但我不确定你是否检查了正确的答案。例如,code4life的答案将无法捕获#N/A值。但是它可以很容易地进行更正:代码应该使用WorksheetFunction.IsError。我不能否认这种简单性,但我现在已经在我的解释中添加了一些代码,这样你就可以看到它也是非常简单的。如果您需要捕获特定的 CVErr 值(除了可以通过WorksheetFunction.IsNa捕获的#N/A之外),那么我在这里提出的方法确实是唯一的方法。 - Mike Rosenblum
仍然是非常有用的答案,但很难找到! - Cyril Gandon
显示剩余3条评论

14

您可以使用WorksheetFunction方法:

Globals.ThisAddIn.Application.WorksheetFunction.IsErr(...)
或者
[Your Excel Object].WorksheetFunction.IsErr(...)

IsErr在语义上与Excel工作表函数完全相同,只不过传递的是实际值而不是单元格引用 - 据我所知。


2
快速提示:WorksheetFunction.IsErr 的设计是对于 #N/A 值返回 false。因此,如果要使用这种方法,应该使用 WorksheetFunction.IsError。如果您需要捕获特定的 CVErr 值,则可以使用 WorksheetFunction.IsNA 捕获 #N/A 值,但对于其他特定的 CVErr 类型,您必须使用我下面概述的方法。 - Mike Rosenblum
由于某些原因,WorksheetFunction.IsError() 对我不起作用,但另一种解决方案(测试是否为Int32)确实有效。 - earcam
1
请注意,如果您已经有单元格的值,则使用Application.WorksheetFunction与检查该值的类型相比非常慢,因为它是一个COM互操作函数,必须分派到Excel应用程序。 - Alain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接