zoukankan      html  css  js  c++  java
  • try catch finally

    1. 下面的代码,1和2有什么不同:

    void Test()
    {
    // 1.
    try { }
    catch (Exception) { }
    // 2.
    try { }
    catch { }
    }

    如果用ildasm查看:

    View Code
    .method private hidebysig instance void  Test() cil managed
    {
    // Code size 22 (0x16)
    .maxstack 1
    IL_0000: nop
    .
    try
    {
    IL_0001: nop
    IL_0002: nop
    IL_0003: leave.s IL_000a
    }
    // end .try
    catch [mscorlib]System.Exception
    {
    IL_0005: pop
    IL_0006: nop
    IL_0007: nop
    IL_0008: leave.s IL_000a
    }
    // end handler
    IL_000a: nop
    .
    try
    {
    IL_000b: nop
    IL_000c: nop
    IL_000d: leave.s IL_0014
    }
    // end .try
    catch [mscorlib]System.Object
    {
    IL_000f: pop
    IL_0010: nop
    IL_0011: nop
    IL_0012: leave.s IL_0014
    }
    // end handler
    IL_0014: nop
    IL_0015: ret
    }
    // end of method Form1::Test

    不同的是第一种方式是捕获System.Exception,以及所有继承自它的类。如果你抛出了一个不是继承自System.Exception的对象,该语句就无法捕获。第二种是没有指定数据类型的catch块,称为泛化catch块,捕获的是object数据类型。这是C#2.0之前的情况

    C# 2.0中的行为稍微有别于之前版本的C#。在C# 2.0中,假如遇到用另一种语言写的代码,而且它会引发不是从System.Exception类派生的异常,那么该异常对象会被包装到一个System. Runtime.CompilerServices.RuntimeWrappedException中,后者是从System.Exception派生的。换言之,在C#程序集中,所有异常(无论它们是否从System.Exception派生)都会表现得和从System.Exception派生一样。所以在C#2.0以及以后的版本中,默认情况下上面两种方式是完全等价的

    某些语言(如 C++)允许您引发任何类型的异常。而其他语言(如 Microsoft C# 和 Visual Basic)要求每种引发的异常都派生自 Exception 类。为了保持语言间的兼容性,公共语言运行库 (CLR) 在 RuntimeWrappedException 对象中包装不是从 Exception 派生的对象。

    使用RuntimeCompatibilityAttribute来指定是否包装non-cls异常。默认情况是true。

    View Code
    namespace System.Runtime.CompilerServices
    {
    // Summary:
    // Specifies whether to wrap exceptions that do not derive from the System.Exception
    // class with a System.Runtime.CompilerServices.RuntimeWrappedException object.
    // This class cannot be inherited.
    [Serializable]
    [AttributeUsage(AttributeTargets.Assembly, Inherited
    = false, AllowMultiple = false)]
    public sealed class RuntimeCompatibilityAttribute : Attribute
    {
    // Summary:
    // Initializes a new instance of the System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
    // class.
    public RuntimeCompatibilityAttribute();

    // Summary:
    // Gets or sets a value that indicates whether to wrap exceptions that do not
    // derive from the System.Exception class with a System.Runtime.CompilerServices.RuntimeWrappedException
    // object.
    //
    // Returns:
    // true if exceptions that do not derive from the System.Exception class should
    // appear wrapped with a System.Runtime.CompilerServices.RuntimeWrappedException
    // object; otherwise, false.
    public bool WrapNonExceptionThrows { get; set; }
    }
    }

    例如在程序的AssemblyInfo.cs中加上以下代码:

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

    假如有下面的函数:

    public class MyClass
    {
    public static void Add()
    {
    try
    {
    //do something.
    }
    catch (Exception)
    {
    }
    catch
    { }
    }
    }

    编译它,不会有任何的warning。如果把AssemblyInfo中的这一行注释掉,就会产生编译warning:

    Warning 1 A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a System.Runtime.CompilerServices.RuntimeWrappedException. c:\users\xiongy.corp\documents\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs 32 13 ConsoleApplication1

    这个warning是由最后一个无参的catch引起的,因为最后一个无参catch永远不会被执行。

    避免使用异常处理来处理预料之中的情况

      和大多数语言一样,在C#中引发一个异常,会对性能造成不利影响,尤其是在负责错误处理的基础结构第一次加载的时候。由于引发异常会引发性能问题,所以开发者应当尽量避免为预料之中的情况或者正常的控制流引发异常。不要用异常来验证用户输入的数据。相反,开发者应该在尝试转换之前对数据进行检查,甚至可以考虑从一开始就防止用户输入无效的数据。

    Note that you should rarely catch the Exception base class, but a more specific exception class that is appropriate for the error that you anticipate. There is usually no point in catching an exception that you don't know how to handle.

    2. 下面两个有什么不同:

    void Test()
    {
    // 1.
    try { }
    catch (Exception ex) { throw ex; }
    // 2.
    try { }
    catch (Exception) { throw; }
    }

    "throw ex" re-throws the exception object from that point. This is generally bad, since it destroys the useful call stack information which lead up to the original problem.

    "throw" doesn't overwrite the stack trace from when the exception was originally thrown, so that is the correct way of rethrowing an exception.

    Instead of using "throw ex" in a catch block you should throw a newly created exception containing the information that you want to add, with the original exception as the inner exception. That way you get both the original point of failure, and the point where you caught it and rethrew it.

    so the correct way should be: a, you always specify the exception type. or b, you either just retrow the exception:

    catch (Exception ex) { 
       
    ... 
       
    throw; 
    } 

    or you throw a new exception with the original exception as an inner exception:

    catch (Exception ex) { 
       
    ... 
       
    throw new ApplicationException("Ooops!", ex); 
    } 
    3. using 关键字
    如下的代码:
    public static void Add()
    {
    using (FileStream fs = new FileStream("c:\\test.txt", FileMode.Open))
    {

    }
    }

     

    使用ildasm查看,可以发现,using最终被编译成try finally块:

    View Code
    .method public hidebysig static void  Add() cil managed
    {
    // Code size 35 (0x23)
    .maxstack 3
    .locals init ([
    0] class [mscorlib]System.IO.FileStream fs,
    [
    1] bool CS$4$0000)
    IL_0000: nop
    IL_0001: ldstr
    "c:\\test.txt"
    IL_0006: ldc.i4.
    3
    IL_0007: newobj instance
    void [mscorlib]System.IO.FileStream::.ctor(string,
    valuetype [mscorlib]System.IO.FileMode)
    IL_000c: stloc.
    0
    .
    try
    {
    IL_000d: nop
    IL_000e: nop
    IL_000f: leave.s IL_0021
    }
    // end .try
    finally
    {
    IL_0011: ldloc.
    0
    IL_0012: ldnull
    IL_0013: ceq
    IL_0015: stloc.
    1
    IL_0016: ldloc.
    1
    IL_0017: brtrue.s IL_0020
    IL_0019: ldloc.
    0
    IL_001a: callvirt instance
    void [mscorlib]System.IDisposable::Dispose()
    IL_001f: nop
    IL_0020: endfinally
    }
    // end handler
    IL_0021: nop
    IL_0022: ret
    }
    // end of method MyClass::Add

    4. 空的try块

    如下是winform的Timer类的dispose方法,用反编译工具ilspy查看:

    // System.Threading.TimerBase
    [SecuritySafeCritical, ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    public void Dispose()
    {
    bool flag = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
    }
    finally
    {
    do
    {
    if (Interlocked.CompareExchange(ref this.m_lock, 1, 0) == 0)
    {
    flag
    = true;
    try
    {
    this.DeleteTimerNative(null);
    }
    finally
    {
    this.m_lock = 0;
    }
    }
    Thread.SpinWait(
    1);
    }
    while (!flag);
    GC.SuppressFinalize(
    this);
    }
    }

    This is to guard against Thread.Abort interrupting a process. MSDN says that:

    Unexecuted finally blocks are executed before the thread is aborted.

    This is because in order to recover successfully from an error, your code will need to clean up after itself. Since C# doesn't have C++-style destructors,

    finally and using blocks are the only reliable way of ensuring that such cleanup is performed reliably.

  • 相关阅读:
    第二个月课堂004讲解python之实战之元组(003)_高级讲师肖sir
    第二个月课堂004讲解python之实战之列表(002)_高级讲师肖sir
    多测师课堂_mysql之报错日志(001)高级讲师肖sir
    多测师课堂012_mysql之存储过程(练习和答案)高级讲师肖sir
    linux alias 命令 查看系统设置的命令别名
    前端 CSS 介绍
    前端 CSS语法
    前端 CSS 注释
    前端 CSS 目录
    linux echo 命令 打印字符串
  • 原文地址:https://www.cnblogs.com/bear831204/p/2154985.html
Copyright © 2011-2022 走看看