C# 试试看……抓块总是很贵吗?

C# 试试看……抓块总是很贵吗?,c#,performance,exception,try-catch,C#,Performance,Exception,Try Catch,可能重复: 大家好,, 只是一个关于try.catch block的快速问题。我听说它们使用起来很昂贵,不应该作为程序流程的一部分使用。但是,为了验证电子邮件地址,我使用以下代码 try { MailAddress checkEmail = new MailAddress(testEmail); return true; } catch {

可能重复:

大家好,, 只是一个关于try.catch block的快速问题。我听说它们使用起来很昂贵,不应该作为程序流程的一部分使用。但是,为了验证电子邮件地址,我使用以下代码

        try
        {
            MailAddress checkEmail = new MailAddress(testEmail);

            return true;
        }
        catch
        {
            return false;
        }
由于之前的验证,我不需要捕获很多异常,除非它试图绕过验证。我的问题是,Try…Catch块是否仅在捕获异常时才昂贵,或者无论是否抛出任何异常,它是否总是昂贵

谢谢


编辑:谢谢你的回复。我已经决定,既然检查(在C#中)不是很昂贵,我将坚持使用这种方法。这主要是因为抛出的实际异常很少,因为之前有一些验证步骤可以确保没有人意外输入无效的电子邮件地址。

try..catch
块不应用作程序流控制的工具


如果你不相信,请阅读。

除非有例外,否则它们非常便宜。因此,在预期出现异常时,应该避免使用它们,如上面的示例所示


我认为用户输入错误的例外情况通常是不明智的。内存不足或其他意外故障时的异常是正常的

一般来说,除非抛出异常,否则现代编译器只对
try
块施加最小的开销。它们仍然不应该用于程序流控制,因为它们不像标准流结构那样明显。异常本质上等同于来自语句的。

只有在抛出异常时,异常才是昂贵的。我确信设置一个Try..Catch块的成本是非常小的,但它远远超过了根本不捕获异常和程序崩溃的成本。正如其他人所指出的,Try..Catch块只应用于异常情况。

虽然您确实不应将Try..Catch用于程序流控制,但在今天的实现中,如果代码中实际上没有抛出异常,我不知道有任何性能问题,输入
try
块一点也不昂贵(这并不总是正确的)。然而,抛出和处理异常通常是一个相对昂贵的操作。因此,异常通常应该用于异常事件,而不是正常的流控制

然而,绩效只是一个因素,尤其是在现代世界。例如,如果您只做了一次响应用户操作的操作,那么从性能角度来看,您是否使用异常可能并不重要,即使您本来可以进行主动检查,如果异常发生的速度足够快,用户不会感到震惊。但如果您在一个将运行数十万次的紧密循环中执行某些操作,或者您正在编写一个可能需要处理巨大负载的web应用程序,您可能希望避免在正常情况下使用异常



1十多年前,我负责对.Net 1.1“无接触部署”应用程序进行增强,在该应用程序中引发的第一个异常花费了整整三秒钟的时间。在一个涉及打开用户要求的文件的用例中,这是一个足够的问题,该文件可能不存在,因此我必须在尝试打开该文件之前添加文件存在性检查,这通常是糟糕的编程实践(只要尝试打开该文件并处理异常,如果失败),纯粹是因为等待异常生成的用户体验太差了。但这可能不是我们现在生活的世界。

这取决于语言,但据我所知,在Java中,如果没有抛出异常,那么使用
try
/
catch
几乎没有性能成本


因此,在您使用预验证电子邮件地址的示例中,您所拥有的一切都很好。

try块的开销非常低,因此如果没有引发异常,那么应该不会有明显的惩罚。抛出异常时发生的主要开销是查找处理程序时发生的堆栈遍历-由于缓存异常的位置离源如此之近,我怀疑会有很大的性能问题。理想情况下,虽然您可以事先正确验证输入,但电子邮件验证相当复杂,因此在这种情况下可能不值得。

只是为了扮演魔鬼代言人-我发现使用异常进行流量控制有一个很好的用途:“取消”按钮

如果你有一个函数在某个服务上运行,可能需要10-120分钟,这是在做一系列不同的事情,我发现如果(hascalled)在我的Log()函数中抛出新的JobCancelledException()(该函数记录我所处的每一步)来工作非常棒。它退出当前代码的执行并停止运行作业——这正是我所需要的。我相信有更好的方法可以做到这一点,也许可以通过事件来实现——但就我而言,它非常有效(特别是因为工作不会经常被取消)

除此之外,我100%同意,例外情况永远不应该被用作流控制工具

@科内尔-我对那篇文章有两个词。。。神圣的$hit=)

下面是一个简单的伪代码示例:

Class Job
{
       Public Run(param1,param2,etc...)
       {
             Try
            {
                   Log("Doing Something")
                   DoSomething()

                         Log("Doing Another")
                         DoAnother()

                         Log("This keeps going, etc, inside of these function we make the same Log calls where it makes sense")
                         Etc()
                   }
                   Catch(JobCancelledException)
                   {
                        status="Cancelled"
                   }
            }

              Private Log(ByVal str As String)
              {
                      MessateToUser(str)

                      if(hasCancelled)
                          throw new JobCancelledException
            }

             private SomeEvent_WhenUserPushesCancelButton()
             {
                       hasCancelled=True
             }
}

只有当抛出异常时,它才是昂贵的,但这不是将异常用作正常流控制的借口

如果您可以预先验证某些内容以避免异常首先发生,那么就这样做。例如,与您发布的内容不同,最好是这样的内容:

string invalidAddress = "notvalid@@@@@@lolzors.bomb";
return MailAddressValidator.IsValid(invalidAddress ); // doesn't cause exception
该规则的例外情况是,您必须滚动自己版本的复杂方法(例如,在基类库中找到的没有
TryParse
方法的东西),以避免出现异常情况,即在总体方案中,根本不重要