using关键字的使用

using关键字的主要3个作用:

  • 引入命名空间
  • 创建别名
  • 强制资源清理

一、引入命名空间: 

  命名空间是.NET程序在逻辑上的组织结构,而并非实际的物理结构,是一种避免类名冲突的方法,用于将不同的数据类型组合划分的方式。例如,在.NET中很多的基本类型都位于System命名空间,数据操作类型位于System.Data命名空间。

  using类似于Java语言的import指令,都是引入命名空间(Java中称作包)这种逻辑结构;而不同于C语言中的#include指令,用于引入实际的类库,using引入命名空间,并不等于编译器编译时加载该命名空间所在的程序集,程序集的加载决定于程序中对该程序集是否存在调用操作,如果代码中不存在任何调用操作则编译器将不会加载using引入命名空间所在程序集。因此,在源文件开头,引入多个命名空间,并非加载多个程序集,不会造成“过度引用”的弊端。

  命名空间分为两类:用户定义的命名空间和系统定义的命名空间。用户定义的命名空间是在代码中定义的命名空间。

using System.Data;
using System.Data.Sqlclient;//用于操作SQL数据库

二、为命名空间或类型创建别名

  创建 using 别名,以便更易于将标识符限定到命名空间或类型。

  例子:新建一个控制台应用程序train_console,在.cs中添加如下代码:

 

namespace People {
    namespace Sleeping {
        public class Sleep {
            public Sleep()
            {
                Console.WriteLine("创建睡觉类");
            }
            public void SleepAll()
            {
                Console.WriteLine("人都要睡觉的");
            }
        }
    }
}

 

  在namespace trian_console中添加using引用的别名:

using sleep = People.Sleeping;//为命名空间使用using别名

  在Main函数中添加:

sleep.Sleep s = new sleep.Sleep();
s.SleepAll();

  运行结果如下:

using关键字的使用

三、强制资源清理

  C# 通过 .NET Framework 公共语言运行库 (CLR) 中的GC(Garbage Collection)自动释放用于存储不再需要的对象的内存。内存的释放具有不确定性;一旦 CLR 决定执行垃圾回收,就会释放内存。

 

  因为非托管资源不受GC控制,对象必须调用自己的Dispose()方法来释放,这就是所谓的Dispose模式。所以,通常最好尽快释放诸如文件句柄和网络连接这样的有限资源。

 

  using 语句允许程序员指定使用资源的对象应当何时释放资源。为 using 语句提供的对象必须实现IDisposable接口。此接口提供了Dispose()方法,该方法将释放此对象的资源。

  下面的示例显示用户定义类可以如何实现它自己的 Dispose 行为。注意类型必须从IDisposable继承。

  新建一个控制台应用程序,添加一个类C(用于测试using释放资源的过程):

class C : IDisposable {
        public void UseLimitResource()
        {
            Console.WriteLine("使用有限的资源");
        }
        void IDisposable.Dispose()
        {
            Console.WriteLine("释放有限的资源");
        }
}

 

  在Main中添加:

Console.WriteLine("使用using释放资源:");
using (C c = new C()) //释放资源 
{
      c.UseLimitResource();
}
Console.WriteLine("资源成功释放!");

  运行结果如下:

using关键字的使用

 

【规则】

  • using只能用于实现了IDisposable接口的类型,禁止为不支持IDisposable接口的类型使用using语句,否则会出现编译时错误;
  • using语句适用于清理单个非托管资源的情况,而多个非托管对象的清理最好以try-finnaly来实现,因为嵌套的using语句可能存在隐藏的Bug。内层using块引发异常时,将不能释放外层using块的对象资源。
  • using语句支持初始化多个变量,但前提是这些变量的类型必须相同

 

using和try-catch-finally的使用异同

  try-catch-finally 一起使用的常见方式是:在try块中获取并使用资源,在catch块中处理异常情况,并在finally块中释放资源。

  共同点:都可以释放资源  
  不同点:
    try-catch-finally可以用来捕获异常并处理,using不行;
    using可以创建别名,导入命名空间 ,try-catch-finally不行;
    using会在资源超出范围后主动释放对象,try-catch-finally要程序员自己写释放对象的代码

两者在处理操作数据库时的使用

  很明显,Dispose方法是一个外部方法,系统并不会帮你调用。为了尽早释放对象所占用的资源,所以需要保证Dispose方法能尽早被执行。那么在.Net中提供了一个比较简便的方法,就是对于实现了IDisposable接口的类型对象提供了using语句。
  对于操作数据库,使用using语句可以如下:

    using( SqlConnection sqlConn = new SqlConnection( yourConnectionString ) )
    {
        sqlConn.Open();//Open connection
        //Operate DB here using "sqlConn"   
        sqlConn.Close();//Close connection
    }

  但是有时候当多个对象需要释放的时候,例如:

    SqlConnection sqlConn = new SqlConnection( yourConnectionString );
    SqlCommand sqlComm = new SqlCommand( yourQueryString, sqlConn );
    using(sqlConn as IDisposable)
    using(sqlComm as IDisposable)
    {
        sqlConn.Open();//Open connection
        sqlComm.ExecuteNonQuery();//Operate DB here
    }

  这时候要特别注意,需要确保在发生异常的情况下,所有对象都能正常释放。显然,这段程序块,当构造“sqlComm”对象发生异常,会造成“sqlConn”对象无法及时被释放。虽说构造函数内部很少发生异常,或者说编写程序的时候要尽量避免从构造函数内向外散发异常。不过这里所说的意思是,要尽量把需要释放的对象放到using或者try-catch程序块,并作局部的异常处理,避免异常造成有些对象没有被释放。那么改进的方法,例如可以如下。

    using( SqlConnection sqlConn = new SqlConnection( yourConnectionString ) )
    using( SqlCommand sqlComm = new SqlCommand( yourQueryString, sqlConn ) )
    {
        try
        {
            sqlConn.Open();//Open connection
            sqlComm.ExecuteNonQuery();//Operate DB here
        }
        catch( SqlException err )
        {
            MessageBox.Show( err.Message );
        }
        catch( Exception err )
        {
            MessageBox.Show( err.Message );
        }
    }

  (如上,即使在构造“sqlComm”出现异常,也会释放“sqlConn”对象。)
  但是对于using程序块来说,它有两个限制。
    第一个就是using所对应的对象必须继承IDisposable,如果此对象没有继承IDisposable接口的话,系统会提示编译错误。
    例如:

  using( string strMsg = "My Test" )
  Debug.WriteLine( strMsg );//Can't be compiled

 

    第二个using对象检查是静态类型检查,并不支持运行时类型检查,因此如下形式也会出现编译错误。

 

    SqlConnection sqlConn = new SqlConnection( yourConnectionString );
    object objConn = sqlConn;
    using ( objConn )
    {
        Debug.WriteLine( objConn.ToString() );//Can't be compiled
    }

    不过对于后者,可以通过“as”来进行类型转换方式来改进。

    SqlConnection sqlConn = new SqlConnection( yourConnectionString );
    object objConn = sqlConn;
    using ( objConn as IDisposable )
    {
        Debug.WriteLine( objConn.ToString() );
    }

 

    对于Dispose函数的调用来说,使用using程序块来完成只是最常用的方法,除此外,还可以用try-finally来完成,例如:

 

    SqlConnection sqlConn = new SqlConnection( yourConnectionString );
    try
    {
        sqlConn.Open();
        //Operate DB here using "sqlConn"
    }
    finally
    {
        if( sqlConn != null )
            sqlConn.Dispose();
    }

  

完整例子如下:

  新建一个控制台应用程序,再新建一个类using_sql,代码如下:

    class using_sql {
        private static string constr = "Data Source=.;Initial Catalog=Csharp;Persist Security Info=True;User ID=sa;Password=huang_bx";
        public static void SqlFun()
        {
            Console.WriteLine("使用using方法");
            using (SqlConnection conn = new SqlConnection(constr))
            {
                conn.Open();
                string cmdstr = "select * from users";
                SqlCommand cmd = null;
                try
                {
                    cmd = new SqlCommand(cmdstr, conn);
                    SqlDataReader sdr = cmd.ExecuteReader();
                    while (sdr.Read())
                    {
                        Console.WriteLine("学号:{0}  姓名:{1}", sdr["UserID"].ToString().Trim(), sdr["UserName"].ToString().Trim());
                    }
                    Console.WriteLine("Connection还未关闭!");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("command出现异常:{0}", ex.Message.ToString());
                }
                finally
                {
                    cmd.Dispose();
                }
                Console.WriteLine("Connection已经关闭!");
                Console.WriteLine();
                Console.WriteLine();
            }

        }

        public static void sqltrycatch()
        {
            Console.WriteLine("使用try-catch-finally");
            //使用try-catch-finally
            SqlCommand cmd1 = null;
            SqlConnection conn1 = null;
            try
            {
                conn1 = new SqlConnection(constr);
                conn1.Open();
                string cmdstr = "select * from users";
                cmd1 = new SqlCommand(cmdstr, conn1);
                SqlDataReader sdr = cmd1.ExecuteReader();
                while (sdr.Read())
                {
                    Console.WriteLine("学号:{0}  姓名:{1}", sdr["UserID"].ToString().Trim(), sdr["UserName"].ToString().Trim());
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("command出现异常:{0}", e.Message.ToString());
            }
            finally
            {
                cmd1.Dispose();
                conn1.Dispose();
            }
        }
    }

  在Main函数中添加:

//using 在 操作数据库时的使用
Console.WriteLine("using 在操作数据库时的使用:");
using_sql.SqlFun();
using_sql.sqltrycatch();

  运行结果如下:

using关键字的使用

  为了及早释放对象所占用的非托管资源,因此要保证Dispose方法能在使用完对象后被调用,.Net提供了using程序块和try-finally程序块两个方法,两者并没有太大的区别,可能使用using能使程序看得比较简明,但是为了防止异常,需要在using中加入try-catch,这样反而不如try-finally看得舒服,不过这也只是我个人的看法。总的来说,只要把方法合理整合到应用程序当中才是最重要的。

 

 

参考资料:百度百科

                http://www.cnblogs.com/falla/archive/2010/02/01/1660832.html

 

 

 

上一篇:匿名函数和扩展函数


下一篇:(DDS)正弦波形发生器——幅值、频率、相位可调(一)