迭戈

博客园 首页 新随笔 联系 管理

对于Try catch finally,大家应该都不陌生,您接触的写法可能会是下面的记几种类型:

Try catch (您可以匹配多个catch)

 

            try
            {
            }
            
catch (Exception)
            {
                
throw;
            }

 

Try finally 

            try
            {
            }
            
finally
            {
            }

 

Try catch finally (同样,你一样可以匹配多个catch)

Try catch finally
            try
            {
            }
            
catch (ArgumentNullException e)
            { }
            
catch (Exception ex)
            { }
            
finally
            {
            }

 

 在这里,finally的作用简单的一句话说就是“无论try里面的代码正常执行或者发生异常,都会继续执行finally里面的代码”,所以我们一般会在finally里面执行我们的一些清理操作。尤其对于操作一些非托管资源或者比较珍贵的资源的时候,执行必要的清理操作显得尤为重要,具体的解释您可以参考MSDN

说了这些,我们来看看try finally,不知道您平时是使用try finally,还是会使用更简洁的语法using {}。对于using, 我这里并不是想详细的解释它的用法,如果您想了解,您请看这里。我们都知道using只是为了让语法变的更简洁而已,我不知道在这里用语法糖这个词来形容它是否合适。为了验证try finally和using是否一致,我再次查看了编译之后的代码(这里我还是使用MSDN的例子):

 

代码
            {
                Font font1 
= new Font("Arial"10.0f);
                
try
                {
                    
byte charset = font1.GdiCharSet;
                }
                
finally
                {
                    
if (font1 != null)
                        ((IDisposable)font1).Dispose();
                }
            }

 

 

我们看一下编译之后的结果(我只是截取了有用的部分代码):

 

using
  .try
  {
    IL_0012:  nop
    IL_0013:  ldloc.
0
    IL_0014:  callvirt   instance uint8 [System.Drawing]System.Drawing.Font::get_GdiCharSet()
    IL_0019:  stloc.
1
    IL_001a:  nop
    IL_001b:  leave.s    IL_002f
  }  
// end .try
  finally
  {
    IL_001d:  nop
    IL_001e:  ldloc.
0
    IL_001f:  ldnull
    IL_0020:  ceq
    IL_0022:  stloc.
3
    IL_0023:  ldloc.
3
    IL_0024:  brtrue.s   IL_002d
    IL_0026:  ldloc.
0
    IL_0027:  callvirt   instance 
void [mscorlib]System.IDisposable::Dispose()
    IL_002c:  nop
    IL_002d:  nop
    IL_002e:  endfinally
  }  
// end handler

 

 

using
  .try
  {
    IL_0041:  nop
    IL_0042:  ldloc.
0
    IL_0043:  callvirt   instance uint8 [System.Drawing]System.Drawing.Font::get_GdiCharSet()
    IL_0048:  stloc.
1
    IL_0049:  nop
    IL_004a:  leave.s    IL_005c
  }  
// end .try
  finally
  {
    IL_004c:  ldloc.
0
    IL_004d:  ldnull
    IL_004e:  ceq
    IL_0050:  stloc.
2
    IL_0051:  ldloc.
2
    IL_0052:  brtrue.s   IL_005b
    IL_0054:  ldloc.
0
    IL_0055:  callvirt   instance 
void [mscorlib]System.IDisposable::Dispose()
    IL_005a:  nop
    IL_005b:  endfinally
  }  
// end handler

 

 没什么区别,不是吗?到这里我产生两个疑问,1. 那么对于try catch和try catch finally编译之后会是什么样子呢? 2. 如果using里面的代码产生异常怎么办呢?于是我编译了try catch finally代码:

Try catch finally
  .try
  {
    .
try
    {
      IL_006e:  nop
      IL_006f:  ldloc.
0
      IL_0070:  callvirt   instance uint8 [System.Drawing]System.Drawing.Font::get_GdiCharSet()
      IL_0075:  stloc.
1
      IL_0076:  nop
      IL_0077:  leave.s    IL_007e
    }  
// end .try
    catch [mscorlib]System.Object 
    {
      IL_0079:  pop
      IL_007a:  nop
      IL_007b:  nop
      IL_007c:  leave.s    IL_007e
    }  
// end handler
    IL_007e:  nop
    IL_007f:  leave.s    IL_0093
  }  
// end .try
  finally
  {
    IL_0081:  nop
    IL_0082:  ldloc.
0
    IL_0083:  ldnull
    IL_0084:  ceq
    IL_0086:  stloc.
2
    IL_0087:  ldloc.
2
    IL_0088:  brtrue.s   IL_0091
    IL_008a:  ldloc.
0
    IL_008b:  callvirt   instance 
void [mscorlib]System.IDisposable::Dispose()
    IL_0090:  nop
    IL_0091:  nop
    IL_0092:  endfinally
  }  
// end handler

 

你仔细看上面的代码,编译器把try catch finally块分解了,新增加了一个try,把try catch块放在 里面,外面套嵌了finally,看来虽然我们自己把try catch finally三者写在一起,当成一个"块",但是编译器会分开处理。

那么对于using产生异常的时候会怎么样呢?我们看下面的代码:

随便定义一个类
    public class Test : IDisposable
    {
        
public int ID;

        
#region IDisposable Members

        
public void Dispose()
        {
            Console.WriteLine(
".......................");
        }

        
#endregion
    }

 

            using (var test = new Test())
            {
                test.ID 
= Int32.Parse("a");
            }

 

上面的代码执行肯定会抛出异常,但是您如果强制继续执行的话,你会看到"............................" 的输出。我们的目的达到了,虽然程序产生了异常,但是我们的清理资源的代码还是执行了。但是这会出来一个很不友好的界面,告诉你程序挂掉了。我想任何一个用户都不希望看到这个。那我们怎么办呢?是继续用代码貌似不够简洁的Try catch finally还是在using里面加上catch来捕获异常呢?写成这种形式吗?

加强版的using
            using (var test = new Test())
            {
                
try
                {
                    test.ID 
= Int32.Parse("a");
                }
                
catch (Exception) { }
            }

 

 这样的语法编译出来和Try catch finally是一样的效果,但是代码要简洁一些。但是每次用using我都需要自己手动加上上面的代码,让我觉得很不好。还好vs里面using是通过Code Snippets来实现的,所以我考虑可以在这里面动一动手脚了。于是我添加了一个新的Snippets文件,将using里面的内容拷过来,修改如下:

 

usingTry
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    
<CodeSnippet Format="1.0.0">
        
<Header>
            
<Title>usingTry</Title>
            
<Shortcut>usingTry</Shortcut>
            
<Description>Code snippet for using statement add Try</Description>
            
<Author>Microsoft Corporation</Author>
            
<SnippetTypes>
                
<SnippetType>Expansion</SnippetType>
                
<SnippetType>SurroundsWith</SnippetType>
            
</SnippetTypes>
        
</Header>
        
<Snippet>
            
<Declarations>
                
<Literal>
                    
<ID>resource</ID>
                    
<ToolTip>Resource to use</ToolTip>
          
<Default>resource</Default>
                
</Literal>
        
<Literal>
          
<ID>expression</ID>
          
<ToolTip>Exception type</ToolTip>
          
<Function>SimpleTypeName(global::System.Exception)</Function>
        
</Literal>
            
</Declarations>
            
<Code Language="csharp"><![CDATA[
      using($resource$)
      {
          try 
          {            
              $selected$
          }
          catch ($expression$)
          {
              $end$
          }
      }
]]>
            
</Code>
        
</Snippet>
    
</CodeSnippet>
</CodeSnippets>

 

 

 

 

至此,完成了一个加强版的using,和使用普通的using是一样的。 

 

posted on 2010-01-17 22:23  Will Meng  阅读(5828)  评论(16编辑  收藏  举报