简体   繁体   English

C#中的3个catch块变体之间有什么区别('Catch','Catch(Exception)'和'Catch(Exception e)')?

[英]What is the difference between the 3 catch block variants in C# ( 'Catch', 'Catch (Exception)', and 'Catch(Exception e)' )?

In C#, what is the difference Between 'Catch', 'Catch (Exception)', and 'Catch(Exception e)' ? 在C#中,'Catch','Catch(Exception)'和'Catch(Exception e)'之间有什么区别?

The MSDN article on try-catch uses 2 of them in its examples, but doesn't explain the difference in usage purposes. 关于try-catchMSDN文章在其示例中使用了其中的两篇,但没有解释使用目的的差异。

try
{}
catch 
{}

try 
{}
catch (Exception)
{}

try
{}
catch(Exception e)
{}

How do these differ? 这些有何不同? Which ones catch all exceptions, and which ones catch specific exceptions? 哪些会捕获所有异常,哪些异常捕获?

No one has yet mentioned the historical aspect of this question. 还没有人提到这个问题的历史方面。

In .NET it is legal to throw an object that does not derive from Exception . 在.NET中,抛出一个不是从Exception派生的对象是合法的。 (It is not legal in C#, but it is in some other managed languages.) Many people are unaware of this fact, but it is legal. (它在C#中不合法,但它在其他一些托管语言中。)许多人不知道这个事实,但它是合法的。 Since that is crazy , in .NET 2.0 the default was changed: if you attempt to throw something that is not an exception then it is automatically wrapped in the RuntimeWrappedException class which obviously is an exception. 由于这很疯狂 ,在.NET 2.0中默认值已经改变:如果你试图抛出一些不是异常的东西,那么它会自动包装在RuntimeWrappedException类中,这显然一个例外。 That object is then thrown. 然后扔掉那个对象。

Because of this oddity, in C# 1.0 it was common to see code that did both: 由于这种奇怪的原因,在C#1.0中,通常会看到同时执行这两种操作的代码:

try
{ do something }
catch(Exception) 
{ handle the exception }
catch
{ handle the thrown non-exception }

And in fact there were security and correctness issues; 事实上,存在安全性和正确性问题; there are situations in which for security reasons you must catch anything that is thrown (possibly to re-throw it) and people would think reasonably that catch(Exception) caught everything, but it didn't. 在某些情况下,出于安全原因,你必须捕获任何抛出的东西(可能重新抛出它),人们会合理地认为catch(Exception)捕获了所有东西,但事实并非如此。

Fortunately since .NET 2.0 things have been more sensible; 幸运的是,自.NET 2.0以来,事情变得更加明智; you can rely on catch {} , catch(Exception) {} and catch(Exception ex) {} to all catch everything should you need to. 您可以依赖catch {}catch(Exception) {}catch(Exception ex) {}来捕获所有需要的东西。

And finally: if for some crazy reason you want to turn on the C# 1.0 behavior, you can put 最后:如果出于某些疯狂的原因你想要打开C#1.0行为,你可以放

[assembly:System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows = false)]

in your program. 在你的程序中。

In short... 简而言之...

Catch without a parameter will receive any exception but provide no means to address it. 没有参数的Catch将收到任何异常,但没有办法解决它。

Catch (Exception) will essentially do the same thing, because you've specified the root Exception type. Catch (Exception)基本上会做同样的事情,因为你已经指定了根Exception类型。 As opposed to Catch (IOException) which would only catch the IOException type. Catch (IOException)相反,它只捕获IOException类型。

Catch (Exception ex) catches all exceptions and provides a means to address it via the ex variable. Catch (Exception ex)捕获所有异常并提供通过ex变量解决它的方法。

Read more: http://msdn.microsoft.com/en-us/library/ms173160.aspx 阅读更多: http//msdn.microsoft.com/en-us/library/ms173160.aspx

First version catches all exceptions deriving from the Exception class. 第一个版本捕获从Exception类派生的所有异常。

The second version catches specified exception. 第二个版本捕获指定的异常。

The third version catches a specified exception with a declared name. 第三个版本捕获具有声明名称的指定异常。 Then in the catch block you can use this object, for example, to see the complete error: e.ToString(); 然后在catch块中,您可以使用此对象,例如,查看完整的错误: e.ToString();

Read more here . 在这里阅读更多。

All of them do basically the same thing, the difference being the amount of information they provide about the error. 所有这些都基本相同,不同之处在于它们提供的有关错误的信息量。

catch (foo ex) {} will filter out all exceptions, except those that can be cast to type foo . catch (foo ex) {}将过滤掉所有异常,除了那些可以强制转换为foo类型的异常。 It also gives you the instance of the error for you to work on. 它还为您提供了错误的实例供您使用。

catch (foo) {} does the same as above, but it doesn't give you the instance of the exception. catch (foo) {}与上面的相同,但它不会为您提供异常的实例。 You'll know the type of the exception, but won't be able to read information from it. 您将知道异常的类型,但无法从中读取信息。

Notice that in both of those cases, if the type of the exception is Exception , they'll catch all exceptions. 请注意,在这两种情况下,如果异常的类型是Exception ,它们将捕获所有异常。

catch {} catches all exceptions. catch {}捕获所有异常。 You don't know the type it caught and you can't access the instance. 您不知道它捕获的类型,您无法访问该实例。

You can choose which one to use based on how much information you need from the exception should it be caught. 您可以根据捕获异常所需的信息来选择使用哪一个。

Regardless of which one you use, you can pass the caught exception forward by using the command throw; 无论您使用哪一个,都可以使用命令throw;传递捕获的异常throw; (without arguments). (没有参数)。

In your example, nothing, since you're not doing anything with the exception. 在你的例子中,什么都没有,因为你没有做任何异常的事情。 But to clarify… 但要澄清......

  • This catches everything but does nothing with the exception. 这会抓住一切,但除了例外之外什么也不做。

     catch {} 

    This is only useful when you want to say guarantee a return from a method. 这仅在您想要保证从方法返回时才有用。

  • This catches only exceptions of type Exception (which is everything) but does nothing with the exception. 这只捕获Exception类型的Exception (这是一切)但对异常没有任何作用。

     catch (Exception) {} 

    This is useful if you wanted to limit the type of exception being caught by specifying which types you want to handle. 如果要通过指定要处理的类型来限制捕获的异常类型,这将非常有用。 Any other exceptions will bubble up the call stack until a proper handler is found. 任何其他异常都会冒出调用堆栈,直到找到合适的处理程序。

  • This catches only exceptions of type Exception (which is everything) and could do something with the exception, but happens to do nothing 这只捕获Exception类型的Exception (这是一切)并且可以对异常执行某些操作,但碰巧什么都不做

     catch (Exception ex) {} 

    This technique gives you a lot more options. 这种技术为您提供了更多选择。 You could log the exception, inspect the InnerException , etc. And again you can specify which types of exceptions you wish to handle. 您可以记录异常,检查InnerException等。再次,您可以指定要处理的异常类型。

Unless you're re-throwing the exception somehow, all of these are bad practice. 除非你以某种方式重新抛出异常,否则所有这些都是不好的做法。 In general, you should only catch the exceptions you can meaningfully handle and allow anything else to bubble up. 一般情况下,您应该只捕获可以有意义处理的异常,并允许其他任何事情冒泡。

Adding catch(Exception e) will give you access to the Exception object, which contains details about the exception that was thrown, such as its Message and StackTrace; 添加catch(Exception e)将允许您访问Exception对象,该对象包含有关抛出的异常的详细信息,例如Message和StackTrace; it is useful to log this information to help diagnose bugs. 记录此信息以帮助诊断错误很有用。 A simple catch without declaring the exception that you're trying to catch won't give you access to the exception object. 如果没有声明您尝试捕获的异常,那么一个简单的catch就不会让您访问异常对象。

Also, catching the base Exception is generally considered bad practice because it's far too generic, and where possible you should always case for a specific exception first. 此外,捕获基本异常通常被认为是不好的做法,因为它太过于通用,并且在可能的情况下,您应该首先考虑特定的异常。 For example, if you're working with files you might consider the following try/catch block: 例如,如果您正在使用文件,则可以考虑以下try / catch块:

try{
    //open your file and read/write from it here
}catch(FileNotFoundException fe){
    //log the message
    Log(fe.Message);
}catch(Exception e){
    //you can catch a general exception at the end if you must
}finally{
    //close your file
}

At the highest level they are all the same; 在最高级别,他们都是一样的; they all catch exceptions. 他们都抓住了例外。

But to drill down further, in the first case you are catching an exception and doing nothing with it (you don't have a defined type). 但是要进一步向下钻取,在第一种情况下,您正在捕获异常并且不执行任何操作(您没有定义的类型)。 In the second example, you are catching an exception of the Exception type. 在第二个示例中,您将捕获异常类型的异常。 In your last example, you are catching the same Exception type as in example 2 but, now you are putting the exception into a variable that would allow you to show it in a MessageBox or: 在上一个示例中,您将捕获与示例2中相同的异常类型,但现在您将异常放入一个允许您在MessageBox中显示它的变量或:

e.Message

It's important to note as well that exceptions are tiered meaning, if you are catching multiple types of exceptions in the same try/catch block, you go from the most specific exception type to the most general. 重要的是要注意异常是分层意义,如果您在同一个try / catch块中捕获多种类型的异常,则从最具体的异常类型转到最常规异常类型。 Like this: 像这样:

try {
}
catch (SqlException sqlExc) {
}
catch (Exception exc) {
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM