在C#Interop中执行检查工作表是否无错误

在C#Interop中执行检查工作表是否无错误,c#,performance,excel-interop,C#,Performance,Excel Interop,我们需要在大约300万个单元格的大型工作簿中查找公式错误。性能至关重要。我们已经在特殊单元格周围实现了一个包装函数,它允许我们在工作表上找不到错误单元格的情况下捕获异常。类似于: 但问题是,当抛出COM异常时,检查变得非常缓慢。更具体地说,当工作表上出现一个错误时,我们记录了1到4毫秒之间的执行时间。当抛出错误时,我们看到的是大约80ms 除了检查错误的不存在,有没有人有任何创造性的快速替代方法 我们的代码: try { dynamic cellsWithErrors = cells.Sp

我们需要在大约300万个单元格的大型工作簿中查找公式错误。性能至关重要。我们已经在特殊单元格周围实现了一个包装函数,它允许我们在工作表上找不到错误单元格的情况下捕获异常。类似于:

但问题是,当抛出COM异常时,检查变得非常缓慢。更具体地说,当工作表上出现一个错误时,我们记录了1到4毫秒之间的执行时间。当抛出错误时,我们看到的是大约80ms

除了检查错误的不存在,有没有人有任何创造性的快速替代方法

我们的代码:

try
{
  dynamic cellsWithErrors = cells.SpecialCells(cellType, valueType);
  return cellsWithErrors;
}
catch (COMException)
{
  return null;
}         
注意事项:

try
{
  dynamic cellsWithErrors = cells.SpecialCells(cellType, valueType);
  return cellsWithErrors;
}
catch (COMException)
{
  return null;
}         
  • 当错误存在时,发现它们是很好的,因此无需关注这一点

  • 通过使用动态类型而不是范围类型,我已经发现了适度的加速

  • 我们的检查将遍历整个工作簿中的所有工作表。因此,我们也很乐意接受任何适用于工作簿的解决方案,但怀疑它是否存在

  • 我们将此作为VSTO插件的一部分编写,并使用互操作层

已考虑的解决方案

我们可以读取整个范围内的值,并对其进行迭代,但希望看到是否还有其他内容。因为在有错误的情况下,这会更慢

当前想法

所以难题归结为这一点。一方面,SpecialCells在找到结果时速度非常快。但抛出异常可能导致20到80倍的减速。另一方面,从性能上看,阅读一张工作表的整个使用范围是相当一致的:我可以说,它的单元格数量是线性的,有一个小的一次性固定首付款。现在,使用Mike Rosenblum的答案,通过检查单元格值,可能会发现错误:。如果是这样,那么我们就有了另一种检查错误的方法

然后,我们的想法是编写一个主函数,它以所讨论的工作表的大小为轴心。如果它是一个非常大的表(我想我们有一个大约有200万个单元格),那么我们最好只使用SpecialCell,并接受异常发生时的成本。但是对于较小的表,如果异常的成本超过了在整个范围内读取并在内存中迭代的成本,那么我们应该只执行后者


对于这种方法,我们需要确定的关键问题是交叉点是什么:SpecialCell在哪里开始优于read&iterate?我们可能还想利用自己对工作簿的了解,试探性地猜测哪些工作表可能有错误,哪些没有错误。如果我们有时间开发一个,我会发布一个答案。

结果是OP问题的性能统计数据是错误的。它们被记录为在调试模式下运行。所以这个问题的真正答案是:不要在调试模式下进行性能测试。嗯。在调试模式下处理异常肯定要付出巨大的代价,尽管我们注意到我的机器与我的队友的机器有很大的不同,所以可能是我的一些本地调试设置。我相信其他人会对此发表更多评论

在调试模式之外运行时,SpecialCells函数的实际性能平均为4ms。这对于我们的用例来说是完全可以接受的。然而,在发现这一点时,我们已经对代码进行了重构,事实上,性能得到了进一步提高

一线希望 最后,我们采用了混合解决方案。如果有问题的工作表有超过200000个单元格,我们只使用SpecialCells callout,平均花费4ms。但是,如果工作表中的单元格数量少于此数量,我们将读取整个使用范围并遍历其所有单元格,通过查看值来检查错误类型,这与Mike Rosenblum的回答类似:。对我们来说,平均而言,通过<20万个单元循环的成本比调用特殊单元稍微便宜。它使我们的平均成绩从4毫秒下降到3毫秒。虽然温和,但速度还是有所加快