C# 强制类型转换异常

6

我发现一些旧代码抛出并捕获了一些转换异常(每次约20个 :( )

由此带来的性能影响是什么?我应该担心吗,还是开销只在try / catch中?

令人惊讶的是,在C#中关于异常性能的主题缺乏信息。

谢谢,祝好!


最终发现方法本身存在问题,将一个30行的显式转换和try catch语句的怪物,简化成了两行代码。处理10000个项目的时间从3.8秒降至3毫秒。 谢谢大家! - Jake Kalstad
5个回答

11

异常会比大部分平均代码行更加拖慢您的进度。不要进行对象转换然后捕获异常,而是使用条件语句来检查。例如:

错误示范

myType foo = (myType)obj;
foo.ExecuteOperation();

好的

myType foo = obj as myType;
if (foo != null)
{
     foo.ExecuteOperation();
}

1

这有两个不好的原因。

  1. 异常很慢,会有相当大的性能损失。我不认为像Matt指出的那样需要整整一毫秒,但它们足够慢,以至于在正常操作中要避免使用它们。
  2. 除非你有充分的理由,否则不应该捕获空异常。你只是隐藏了问题。最好让程序崩溃,而不是继续运行可能存在危险漏洞的程序。

如果它们只是try { } finally { }组,那就没问题了——没有额外的开销。然而,try { } catch { }既有潜在的危险,也有潜在的缓慢。

至于文档,这很好:http://www.codeproject.com/KB/architecture/exceptionbestpractices.aspx#Don%27tuseexceptionhandlingasmeansofreturninginformationfromamethod18

编辑:刚刚意识到你说的是捕获“空异常”,而不是“捕获空值异常”。无论如何,除非你正在处理IO,否则出于性能考虑,你可能想避免这样做。


0

正如其他人所提到的,当抛出异常时会导致性能消耗大。在某些情况下,无法避免使用异常。

然而,在这个情况下,听起来它们绝对可以避免。

我建议在进行强制转换之前使用 as 关键字。这将告诉您强制转换是否成功,从而完全避免异常的发生:

object someObject;
SomeType typedObject;

// fill someObject

typedObject = someObject as SomeType;

if(typedObject == null)
{
    // Cast failed
}

一个人应该将 if(x is T) y = (T)x; 或者 y = x as T; if(x != null) 结合起来使用。前者也适用于结构体。 - Dykam

0

异常在性能方面是昂贵的。上次我测量时,每个异常抛出和捕获大约需要一毫秒

避免使用异常作为流程控制机制。


他不应该通过抛出异常来处理异常,而是应该优雅地处理它。任何他无法优雅地捕获的异常都是你希望抛出的异常类型,当然如果他小心的话就不应该发生异常。 - Security Hound

-1

如果您没有遇到任何性能问题,并且这是您执行该算法的唯一方法,请继续使用此方法。

也许在尝试转换之前,您可以使用一些if语句来查看是否可以进行转换。


异常很昂贵。在正常操作中使用它们是不好的实践。 - Rei Miyasaka
我从未说过它们不贵。如果你读了我的帖子,我写道只有在他没有遇到性能问题或者这是编写算法的唯一方法时,他才能使用它。 - as-cii
这里的关键是“如果...这是你唯一能实现该算法的方式。”有时候,你必须打破规则。这并不丑陋,但这就是事实。虽然我可能会重构这样的代码以使用TryParse,但问题仍然存在:如果它失败了,你该怎么办? - Mike Hofer
如果你正在编写一个解析大量数据的程序,其中一些可能是整数,使用int.Parse将导致创建一个新的异常对象,其中包含整个堆栈的展开。与此同时,int.TryParse只需要几个时钟周期。另外,我真的想不出一个需要在正常操作中使用异常的算法示例。如果这不是他所询问的正常操作,那么我怀疑他首先就不会提出这个问题--因为显然异常操作是异常的目的。 - Rei Miyasaka
有相当数量的第三方库在内部执行大量的“流程控制异常”。如何检查文件是否存在?打开文件并查看是否失败!在这种情况下,直接检查文件是否存在并没有太大帮助,因为它可能会在您检查之后但在使用之前停止存在。因此,在某些情况下,异常是预期的,并被用作流程控制机制。 - GWLlosa

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