zoukankan      html  css  js  c++  java
  • 为什么建议使用多重using

    什么是多重using(mutiple using)?

    所谓多重using,是指C#的一个特性,即如下的代码结构:
    using (IDisposable d1= ...)
    using (IDisposable d2 = ...)
    {
        
    //operation with d1 and d2
    }

    而下面列的代码结构叫嵌套using(nested using):

    using (IDisposable d1 = ...)
    {
        
    //operation with d1
        using(IDisposable d2 = ...)
        {
            
    //operation with d1 and d2
        }
    }

    为什么建议使用多重using?

    我们知道,使用using结构是用来处理IDisposable的对象。加入我们不用using结构,IDisposable的对象我们可以这样来处理:
    IDisposable d1 = ...
    //operation with d1
    d1.Dispose();

    这样做的缺点也很明显:1)开发者很容易忘记调用d1.Dispose()方法;2)也是最重要的,假如在d1.Dispose()之前发生了exception,那d1.Dispose()方法便不会被执行,于是d1便不能被释放。因此,对于这种模式的改进便是用try-finally的结构:

    IDisposable d1 = ...
    try
    {
        
    //operation with d1
    }
    finally
    {
        d1.Dispose();
    }

    然后,这正是using的实现方式,因此我们使用using结构可使程序更优雅:

    using(IDisposable d1 = ....)
    {
        
    //operation with d1
    }

    那么,当我们要同时处理多个IDisposable的对象时什么方式最好呢?我们首先会想到的是嵌套的using:

    using (IDisposable d1= ...)
    {
        
    //Block 1
        
    //operation with d1
        
    using (IDisposable d2 = ...)
        {
            
    //operation with d1 and d2
        }
    }

    它本身的缺点是,在Block1范围内无法访问到d2这个对象(当然如果要求在这个区域不能访问d2时另当别论)。另一个方面是,当有多重嵌套时,代码缩进很大,显的很不美观。解决很深的嵌套我们可以用try-finally的结构来实现:

    IDisposable d1 = ... //instantiate d1
    IDisposable d2 = ... //instantiate d2
    IDisposable d3 = ... //instantiate d3
    try
    {
        
    //operation with d1, d2, d3
    }
    finally
    {
        d3.Dispose();
        d2.Dispose();
        d1.Dispose();
    }

    乍看起来没什么问题。但是,对于上面的代码假如d1,d2成功的实例化了,程序在执行到IDisposable d3 = ... //instantiate d3这条语句的时候发生了exception,下面的语句便不会执行。这样d1,d2便不能被正确的Dispose。作为解决办法,可以把对象的实例化放到try块中:

    IDisposable d1 = null;
    IDisposable d2 
    = null;
    IDisposable d3 
    = null;
    try
    {
        IDisposable d1 
    = ... //instantiate d1
        IDisposable d2 = ... //instantiate d2
        IDisposable d3 = ... //instantiate d3
        
    //operation with d1, d2, d3
    }
    finally
    {
        d3.Dispose();
        d2.Dispose();
        d1.Dispose();
    }

    这样,程序虽然丑陋了一些,但是似乎解决了对象实例化的时候发生异常的问题。等等,似乎新的问题又出现了:假如d1实例化的时候发生了exception,程序转到了finally语句块,这时d1,d2,d3中部分对象没有实例化,在没有实例化的对象上调用其方法就产生了null reference的exception。作为补救,程序变成了这个样子:

    IDisposable d1 = null;
    IDisposable d2 
    = null;
    IDisposable d3 
    = null;
    try
    {
        IDisposable d1 
    = ... //instantiate d1
        IDisposable d2 = ... //instantiate d2
        IDisposable d3 = ... //instantiate d3
        
    //operation with d1, d2, d3
    }
    finally
    {
        
    if (d3 !=null) d3.Dispose();
        
    if (d2 !=null) d2.Dispose();
        
    if (d1 !=null) d1.Dispose();
    }

    最终,一个简单的需求让程序变的这么丑陋,我们要的是优雅的代码。对于这种情况,不被大家所了解的多重using可很好的解决问题:

    using (IDisposable d1 = ...)
    using (IDisposable d2 = ...)
    using (IDisposable d3 = ...)
    {
        
    //do operation with d1, d2, d3
    }

    很简单哈?就是这么简单就可以解决前述的所有问题。值得一提,在这个结构中对象的释放顺序是和其生成顺序的倒序。

    最后来一个实际应用的例子:
    using (var file = new FileStream("c:\\a.txt", FileMode.Open))
    using (var reader = new StreamReader(file))
    {
        
    //do with reader
    }
    因此能使用多重using就要使用。
  • 相关阅读:
    如何使用sendEmail发送邮件
    Linux curl命令详解
    linux比较两个文件是否一样(linux命令md5sum使用方法)
    strace命令用法详解
    strace用法说明
    ORA-12154 TNS无法解析指定的连接标识符
    VNC远程连接阿里云Linux服务器 图形界面
    pycharm配置Git 代码管理
    FireFox浏览器-xpath快速定位插件:Xpath Checker
    odoo 前端模板引擎 Qweb
  • 原文地址:https://www.cnblogs.com/lsp/p/1643595.html
Copyright © 2011-2022 走看看