【问题标题】:Why can't I write just a try with no catch or finally? [closed]为什么我不能只写一个没有捕获或最终的尝试? [关闭]
【发布时间】:2011-05-31 05:19:58
【问题描述】:

有时我这样做,我也看到其他人也这样做:

VB:

Try
    DontWannaCatchIt()
Catch
End Try

C#:

try 
{ 
    DontWannaCatchIt();
} 
catch {}

我知道我应该抓住每一个重要的异常 我期待并对此采取一些措施,但有时并不重要 -还是我做错了什么?

try 块的这种用法是否不正确,并且至少有一个 catchfinally 块的要求表明了这一点?

更新:

现在我明白了其中的原因,我至少应该对空的 catch 块发表评论,以便其他人了解它为什么是空的。我也应该只捕获我期望的异常。

幸运的是,我正在用 VB 编写代码,所以我可以一口气写出来:

Catch ex As Exception When TypeOf ex Is IOException _
                    OrElse TypeOf ex Is ArgumentException _
                    OrElse TypeOf ex Is NotSupportedException _
                    OrElse TypeOf ex Is SecurityException _
                    OrElse TypeOf ex Is UnauthorizedAccessException
    'I don't actually care.
End Try

【问题讨论】:

  • @asawyer 不,我已经说过我知道我应该捕捉每一个重要的异常,我会使其更加粗体,因为它对你来说不够清晰。
  • 你能举一个例子,你认为一个异常“不够重要,不能被捕获”吗?很可能,那里是你的错误。
  • @Camilo 捕捉每一个重要的异常是一个的想法。您只捕获您可以处理的内容,否则您的应用程序应该可怕地死掉并让别人知道它已经死了,以便程序员可以修复它。
  • @George 已编辑,因为这仍然不是我的意思,我的错。
  • 现在您已经编辑了它,问题在哪里?捕获您可能遇到的重要错误,例如您想要吞下的 IO 问题意味着您需要指定它们,而 c# 对此具有非常好的语法。

标签: c# .net vb.net exception-handling try-catch


【解决方案1】:

没有 catch 或 finally 无效。空的 catch 或 finally 是有效的。空catch意味着你不关心异常,你只是尝试做一些事情,如果它不起作用也没关系,你只是想继续。例如在清理功能中很有用。

【讨论】:

  • 在 VB 和 C# 中空捕获或最终编译。也许它会出现在 FxCop 之类的东西中,在这种情况下,我可以将其配置为忽略它。但我担心这样做是否不好。
  • 一个空的最终没有任何意义,所以我可以想象 FxCop 抱怨。空投通常是深思熟虑的决定,FxCop 不应该抱怨。
【解决方案2】:

另外,如果您不需要对错误采取措施,也许您应该指定程序必须忽略的异常类型。

如果你必须忽略每一个异常,我不明白为什么你不能以这种方式使用 try/catch。

【讨论】:

  • 我已经说过我关心异常,但不是每一个。有时处理它们是徒劳的——假设你的应用程序记录了它迄今为止所做的事情以用于基准测试。如果由于某种 IO 原因我错过了一个日志,我不在乎。
  • 好吧,假设异常对您来说并不重要,我认为这可能是一个好方法。请记住,这将隐藏其他异常,因此如果您不关心 IOException,那么您的记录器可能会引发另一个您看不到的错误。
  • 在这种情况下,我可以编写一个 catch 块来捕获 ImportantExeption
  • 参考记录器示例,您的实现可能会导致 OutOfMemoryException 或其他...因此,如果您不关心 IOException,请将其插入空的 catch 块中。我认为您永远无法确定是否每个例外都是无用的。同样,如果 logger 由于隐藏的异常而没有记录任何内容怎么办?
  • 你说得对,从现在开始我只会捕获我期望的异常。
【解决方案3】:

我听说的原因是,如果您的尝试因任何原因失败,让您控制错误响应比让框架控制它更可取,即黄屏或错误 500。

【讨论】:

  • 我没有让框架控制它,一个空的 catch 意味着“让我控制错误:我不会对此做任何事情”
【解决方案4】:

这通常是一个错误。异常信号,嗯,异常行为;当抛出异常时,它应该意味着出现问题。因此,继续正常的程序流程,就好像没有出错一样是隐藏错误的一种方式,一种拒绝的形式。相反,请考虑您的代码应该如何处理异常情况,并编写代码来实现这一点。由于您掩盖了它而传播的错误比立即出现的错误更难调试。

【讨论】:

  • 每个失败的文件 IO 都会抛出一个异常,这太棒了。但是我有两种可能性:它设法保存了日志,或者没有。如果它没有保存日志,我不在乎,那我为什么要编码呢?另外,日志不保存到磁盘怎么办?向用户弹出错误?如果打扰用户比不保存日志更糟糕怎么办?如果它在没有用户的服务器上怎么办?许多变量会影响在异常情况下做某事的可能性和优势。
  • @CamiloMartin:你的大胡子吓到我了,哈哈
【解决方案5】:

这对您来说并不容易,因为大多数开发人员认为这是不好的做法。

如果后来有人向DontWannaCatchIt() 的主体添加了一个方法调用,确实抛出了一个值得捕获的异常,但它被你的空 catch 块吞噬了怎么办?如果有一些您实际上想要捕获但当时没有意识到的异常怎么办?

如果您绝对必须这样做,请尽量具体说明您要捕获的异常类型。如果没有,也许记录异常是一种选择。

【讨论】:

  • 如果方法叫LogBenchmark,我不指望有人在上面写多线程的生活游戏。
【解决方案6】:

如果你只用 try 编写代码会怎样

try
{
   int j =0;
   5/j;
}

这相当于写

 int j =0;
   5/j;

所以写 try 没有任何意义,它只会增加你的行数。

现在如果你用空的 catch 或 finally 编写 try ,你就是在明确地指示运行时以不同的方式表现。

这就是为什么我认为空的 try 块是不可能的。

【讨论】:

  • 这就是重点,我希望尝试只是意味着“尝试使用空捕获”或“忽略此处的错误”。如果我没有在 catch 上写任何东西,为什么还要写一个 catch?
  • 因为在这种情况下使用空的 catch ,您的代码不会抛出运行时异常,而且有时您只是事先不知道如何处理将来您会遇到的问题
  • @Camilo Martin:我认为这属于“一种语法已经存在,为什么还要再做一个”和“它的形式不好且不常见”的论点。如果你的意思是什么都不做,那就这么说吧。与没有 else 的 if 不同,这将是最接近您所说的示例,try 本身并不像关键字那样明显应该发生什么。此外,与没有 else 的 if 不同,带有空 catch 的 try 不应该是常见的,并且通常被认为是错误的形式,因此有 if 不需要空 else,但没有 try 没有 catch 或 finally。
  • @Gideon 想一想——如果你告诉我“这样做”,这意味着我必须这样做,失败将是不可接受的,但如果你告诉我“尝试这样做”,听起来像是在没有严重后果的情况下失败是可以接受的。 IMO 它很直观,因为这是我用简单的英语所期望的。
  • 呃……不。假设 j 是用户给定的值。如果您不想对用户输入零大惊小怪,请使用 try 和 empty catch。如果你不在那里尝试,程序会因为被零除而发疯,然后退出。
【解决方案7】:

如果你不想抓住它,你为什么首先使用try

try 声明表示您认为可能会出错,catch 表示您可以充分处理出错的情况。

所以在你的估计中:

try
{
    //Something that can go wrong
}
catch
{
    //An empty catch means I can handle whatever goes wrong. If a meteorite hits the
    //datacenter, I can handle it.
}

这个 catch 会吞下任何发生的异常。您对自己的代码有信心,能够优雅地处理任何出错的事情吗?

最好的办法(为了你和你的维护程序员的理智)是明确说明你可以优雅地处理:

try
{
    //Something that could throw MeteoriteHitDatacenterException
}
catch (MeteoriteHitDatacenterException ex)
{
    //Please log when you're just catching something. Especially if the catch statement has side effects. Trust me.
    ErrorLog.Log(ex, "Just logging so that I have something to check later on if this happens.")

}

【讨论】:

  • 我的主要观点仍然是,如果Try 块中的内容有任何问题,可以忽略它,因为它不会影响程序流程中的任何内容。这意味着无论在 try 块中发生什么,即使是最坏的可能性,它对程序的其余部分都无关紧要。
  • 那么你最好的选择是明确声明你是catch (Exception){} 以及为什么你认为你可以处理任何抛出的异常。我得告诉你,如果我在另一个程序员的代码中看到这一点,我的第一个想法会是,“哦,废话。”
  • @George 我知道你的意思,它确实闻起来很糟糕,这就是为什么我担心这种忽略异常的方式(当我完全意识到后果时)可能是错误的,所以也许需要 catch 块,因为我至少应该在上面放 cmets。
  • @Camilo:如果您觉得需要像我在之前的评论中提到的那样有一个 catch 块,那么评论该块是必须的。你想用“为什么”来评论它,你选择做一些有代码味道的事情。
  • 接受,你是对的。它在那里是因为我至少应该对此发表评论道歉,这是完全可以理解的。
【解决方案8】:

是的,这是不正确的。就像goto:每 100 KLoc 一个就可以了,但如果你需要很多,那你就错了。

在没有任何反应的情况下吞下异常是错误处理中最糟糕的事情之一,它至少应该是明确的:

try  
{      
   DontWannaCatchIt(); 
}  
catch 
{
    // This exception is ignored based on Spec Ref. 7.2.a,
    // the user gets a failure report from the actual results, 
    // and diagnostic details are available in the event log (as for every exception)
} 

远观:

错误处理是一个方面:在某些情况下,需要抛出错误并向上传播调用堆栈(例如,您复制文件,复制失败)。

在不同的上下文中调用相同的代码可能需要跟踪错误,但操作要继续(例如,复制 100 个文件,并带有指示哪些文件失败的日志)。

即使在这种情况下,空的 catch 处理程序也是错误的。

在大多数语言中,除了在循环中使用 try+catch 并在 catch 处理程序中构建日志之外,没有其他直接的实现。 (不过,您可以构建一个 mroe 灵活的机制:拥有一个可以抛出或隐藏消息的每个调用线程处理程序。但是,如果没有直接的语言支持,与调试工具的交互会受到影响。)


一个明智的用例是从X() 实现TryX(),但这必须返回有问题的异常。

【讨论】:

  • 阅读我的代码,普通的迅猛龙会被第 30.000 行弄糊涂,所以任何到达第 100.000 行的机会都很渺茫。
【解决方案9】:

存在错误,已被抛出,需要去某个地方。正常代码流已中止,需要清洁风扇。

没有捕获块 = 不确定状态。代码应该去哪里?应该怎么做?

一个空的 catch 块 = 通过忽略它来处理错误。

注意:VBA 有一个卑鄙的“错误继续”...

【讨论】:

  • VBA 适用于几乎一直使用On Error Continue 的人。
【解决方案10】:

不,您应该捕获每个重要的异常。捕获和忽略您不关心的异常是可以的,例如 I/O 错误,如果您无法纠正它并且您不想费心将其报告给用户。

但您需要让 StackOverflowExceptionOutOfMemoryException 等异常传播。或者,更常见的是NullReferenceException。这些异常通常是您没有预料到、无法从中恢复、不应从中恢复且不应被抑制的错误。

如果您想忽略异常,那么很好在代码中为该特定异常显式编写一个空的 catch 块。这清楚地表明您正在忽略哪些异常。非常正确地忽略异常是一种选择加入程序,而不是选择退出程序。拥有一个“忽略所有异常”功能,然后可以覆盖该功能以不忽略特定类型,这将是一个非常糟糕的语言功能。

您如何知道哪些类型的异常很重要且不应被捕获?如果有你不知道的例外怎么办?你怎么知道你最终不会隐藏你不熟悉的重要错误?

try
{
}
// I don't care about exceptions.
catch
{
}
// Okay, well, except for system errors like out of memory or stack overflow.
// I need to let those propagate.
catch (SystemException exception)
{
    // Unless this is an I/O exception, which I don't care about.
    if (exception is IOException)
    {
        // Ignore.
    }
    else
    {
        throw;
    }
}
// Or lock recursion exceptions, whatever those are... Probably shouldn't hide those.
catch (LockRecursionException exception)
{
    throw;
}
// Or, uh, what else? What am I missing?
catch (???)
{
}

【讨论】:

猜你喜欢
  • 2012-09-04
  • 2017-09-12
  • 2021-01-08
  • 2019-04-29
  • 2016-01-10
  • 2014-11-05
  • 1970-01-01
  • 2020-07-31
  • 2012-03-03
相关资源
最近更新 更多