2009-02-02 135 views
30

编写一个C#应用程序,其#1优先级为永远不会崩溃,我应该多久使用一次try-catch块?我应该多久使用一次C#中的try和catch?

我可以在try-catch块中封装方法中的所有语句吗?

public void SomeMethod() 
{ 
    try 
    { 
     // entire contents of the function 
     // library calls 
     // function calls 
     // variable initialization .. etc 
    } 
    catch (Exception e) 
    { 
     // recover 
    } 
} 

将所有内容封装在try-catch块中的缺点是什么?

回答

30

唯一的缺点是当实际抛出异常时。包装代码没有开销,除非发生异常。

此外,您不想使用try/catch来控制流程。考虑一下(糟糕的代码):

try { 

    FileStream fs = File.Open("somefile.txt", FileMode.Open); 

} catch (Exception ex) { 
    MessageBox.Show("The file does not exist. Please select another file"); 
} 

你会从File.Exists等某些东西中获得更多的性能。如:

if(!File.Exists("somefile.txt")) 
    MessageBox.Show("The file does not exist.") 

编辑: 发现MSDN direct quote

查找和设计走 异常沉重的代码可以导致 体面PERF胜利。请记住, 这与try/catch 块无关:只有在投入实际异常时才会产生成本 。您可以使用与您想要的 一样多的try/catch块。使用例外 无偿地是你失去 表现的地方。例如,你应该远离诸如使用 例外控制流。

+2

那么,有*最小*开销。有些,但非常小。 – 2009-02-02 23:50:15

+1

不好的一面是JIT编译器不能内联包含异常处理结构的函数 – 2009-02-27 21:05:49

+17

当您检查它并尝试打开它时,文件可能会停止存在。您*需要* try-catch块以确保您不会崩溃。 – 2009-02-27 21:24:45

1

尝试块有性能开销,如果你这样做,你的整个函数将会运行得慢一些。 catch (Exception e)也是一个坏主意,如果你发现你想要对你所发现的东西做一些有用的事情,并且如果你发现了所有的异常,就不可能知道你应该做什么。

+0

+1用于解释捕获的缺点(例外e)。 – jason 2009-02-03 01:25:24

+1

除非你正在做类似于日志记录和重新投掷的事情。 – 2009-02-03 05:22:09

8

其实,除了记录目的,我很少使用catch块。 finally对我来说更为常见。大多数时候,lockusing做我能做的所有事情(事实上,这也是finally)。

Eric Lippert有一个blog entry on exceptions这可能是有用的。

+1

(或当然是用于顶级UI处理程序) – 2009-02-02 23:51:24

1

你可以做到这一点,尽管几乎在任何给定的环境中运行,还有一个全局异常处理程序,您可以在其中捕获和处理未知错误。

对于Web应用,则在Global.asax,对于一个控制台程序,只是包装你的Main()在一个try/catch,在服务方面,有AppDomain.CurrentDomain.UnhandledException等

你应该换您可以预测哪些异常可能在更具体的块中,但全局异常处理程序应该大大简化您的代码并帮助您解决问题。

-1

你应该在任何时候使用它们一段代码可以引发异常。

你必须小心,捕捉一般例外从来不是一个好主意。你必须决定你想要处理它们的哪一层。

含义越深意味着你想抓住非常具体的注意事项并走向更一般化。在数据库中捕获SqlException。随着你越来越高,你会发现更多的例外,以最终捕捉到最顶层的一般例外。

这样你就可以根据具体情况处理每个异常。一般的例外,你不知道该怎么处理。

+2

*每行*代码都会引发异常。 OutOfMemoryException,ThreadAbortException等等。如果你可以做一些有用的事情,你应该只捕捉它。大多数时候,你不能。 – 2009-02-02 23:52:19

4

一般海事组织最好把试图抓住的小块放在你的控制之外。如果你说:

try 
{ 
    //anything that could possibly go wrong 
    //This kind of thing is only good for Logging IMO and could be done in 
    //Global.asax 
} 

你怎么可能知道在您的捕获方法做的原因可能是什么...

其更好的去:

try 
{ 
    //divide user imputs 
} 
catch(DivideByZeroException) 
{ 
    // tell user bad inputs ect.... 
} 
catch (Exception e) 
{ 
    //If you choose to throw the exception you should 
    //*********************** 
    throw; 
    //VS 
    throw ex; //Throw ex will restart the stack trace 
    // recover 
} 
finally 
{ 
    //Clean up resources and continue 
} 

在哪终于始终运行

3

这个问题的关键是以下行:

// recover 

为了能够恢复,你必须知道什么和如何恢复。这就是假设它有可能恢复,但通常情况并非如此。

当您知道如何处理异常,何时知道如何从中恢复以及何时确定无需离开应用程序就可以执行此操作时,只应使用catch部分的try/catch/finally吞下异常不一致或无效的状态。

如果您可以在您的应用程序中针对所有方法调用中的所有可能的异常执行此操作,那么请继续前进,否则您可能需要重新考虑您的#1优先级(有时候,快速失败是比尝试保留应用程序在出现问题时仍然存在,并且稍后难以调试崩溃)。

0

我们目前的应用程序有一个类似的任务:永不崩溃。总是优雅地退出。为此,您必须确保每行代码都包含在try-catch块中,或者只能由代码调用,否则它的异常可能会触发。另外,为防止未捕获的异常,我们将一个UnhandledExceptionEventHandler附加到AppDomain.CurrentDomain。

2

如果你能够有意义地处理它,你应该只捕获并停止异常而不重新抛出异常。否则,它是一个错误,它应该传播。

我认为当他们说“这个应用程序永远不会崩溃”时,会有一个隐含的要求,它的行为是正确的。只有停止有意义的异常处理才能满足行为正确的要求。

通常,应用程序将有一个顶级的catch块来捕获和记录未处理的异常。这些应该很少出现(也许你的要求可以被解释为意味着这些不应该发生)。如果您在代码中的其他任何位置捕获并停止异常,则可能无法发现这些问题。如果你捕获日志并停止在你的代码的许多其他部分,那么从关注点分离的角度来看,你的应用程序构造不佳。

23

这是一个很大的话题。对于异常处理的最佳做法,一些优秀的讨论开始here和宗教战争准备...

Code Analysis Team Blog

Martin Fowler - Fail Fast

MSDN on Exception Handling

Checked vs Unchecked Exceptions

我自己的看法是,大多数情况下,你大量使用“尝试/最终”,但“抓”很少。问题是,如果您尝试在错误的实例中捕获并处理异常,则可能会无意中将您的应用程序置于不良状态。通常,使用开发和测试来了解您实际需要处理异常的位置。那些将是你无法检查的地方。即你不应该真的需要处理nullreference或filenotfound,因为你可以主动检查那些。只有你知道的例外可能会发生,但你无能为力。除此之外,为了您的数据状态,让它崩溃。

如果你吞咽异常,通常意味着你不理解你的程序或你为什么会得到异常。在C#中的System.Exception捕获时的代码海报孩子气味......

-3

尝试捕捉:

try{ 

} 
catch (NullReferenceException en) 
{ 

} 
-1
public void functionName 
{ 
    try 
    { 
    //your codes 
    //sometimes 'return' shows exceptions 
    } 
    catch(Exception e) 
    { 
    messagebox.show(e.Tostring()); //to know what is the exception 
    } 
    finally 
    { 
    } 
} 
1

我会尽量避免try catch块一般。我更喜欢使用循环来强制用户遵守应用程序的规则。例如,如果用户只输入一个int比一个int X等于或小于我会使用:

if (input > x) 
{ 
    Console.WriteLine("Invalid input. Please enter a number that is equal to or less than x."); 
{...} 
} 

,而不是使用:

catch (IndexOutOfRangeException) 
{ 
     //error message here 
} 

从我个人的经验,我发现它更容易编写,因为您可以避免将代码封装在try块(守护代码)中。

当然,总会有时间使用try catch是不可避免的 - 我只是想尽可能地解决它。