在C#中“使用”有什么用处

时间:2008-09-16 18:23:46

标签: c# using using-statement

用户kokos通过提及using关键字回答了精彩的Hidden Features of C#问题。你能详细说明吗? using有什么用途?

29 个答案:

答案 0 :(得分:440)

using语句的原因是确保对象在超出范围时立即处理,并且不需要显式代码来确保对象发生这种情况。

Understanding the 'using' statement in C# 一样,.NET CLR会转换

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

{ // Limits scope of myRes
    MyResource myRes= new MyResource();
    try
    {
        myRes.DoSomething();
    }
    finally
    {
        // Check for a null resource.
        if (myRes != null)
            // Call the object's Dispose method.
            ((IDisposable)myRes).Dispose();
    }
}

答案 1 :(得分:121)

由于很多人仍然这样做:

using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

我想很多人仍然不知道你能做到:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}

答案 2 :(得分:95)

这样的事情:

using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

    // Execute SQL statement here on the connection you created
}

这个SqlConnection将被关闭而无需显式调用.Close()函数,即使抛出异常也会发生,而不需要{{1> 1}} / try / catch

答案 3 :(得分:30)

使用可以用来调用IDisposable。它也可以用于别名类型。

using (SqlConnection cnn = new SqlConnection()) { /*code*/}
using f1 = System.Windows.Forms.Form;

答案 4 :(得分:21)

使用,

using (var foo = new Bar())
{
  Baz();
}

实际上是try / finally块的简写。它等同于代码:

var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

当然,您会注意到,第一个代码段比第二个代码段更简洁,并且即使抛出异常,您也可能希望执行许多类型的事务清理。因此,我们提出了一个我们称之为Scope的类,它允许您在Dispose方法中执行任意代码。因此,例如,如果您有一个名为IsWorking的属性,您在尝试执行操作后总是想要设置为false,那么您可以这样做:

using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

您可以详细了解我们的解决方案及其衍生方式here

答案 5 :(得分:10)

我过去经常使用它来处理输入和输出流。你可以很好地嵌套它们,它会消除你经常遇到的许多潜在问题(通过自动调用dispose)。例如:

        using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
        {
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (System.IO.StreamReader sr = new StreamReader(bs))
                {
                    string output = sr.ReadToEnd();
                }
            }
        }

答案 6 :(得分:10)

Microsoft文档声明使用具有双重功能(https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx),作为指令语句。作为语句,正如其他答案中所指出的那样,关键字基本上是语法糖,用于确定处置 IDisposable 对象的范围。作为指令,它通常用于导入名称空间和类型。另外,作为一个指令,您可以为名称空间和类型创建别名,如书中所述" C#5.0在果壳中:权威指南" (http://www.amazon.com/5-0-Nutshell-The-Definitive-Reference-ebook/dp/B008E6I1K8),Joseph和Ben Albahari。一个例子:

namespace HelloWorld
{
    using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
    public class Startup
    {
        public static AppFunc OrderEvents() 
        {
            AppFunc appFunc = (IDictionary<DateTime, string> events) =>
            {
                if ((events != null) && (events.Count > 0))
                {
                    List<string> result = events.OrderBy(ev => ev.Key)
                        .Select(ev => ev.Value)
                        .ToList();
                    return result;
                }
                throw new ArgumentException("Event dictionary is null or empty.");
            };
            return appFunc;
        }
    }
}

这是明智的选择,因为滥用这种做法会损害一个人的代码的清晰度。关于C#别名的一个很好的解释,也提到了DotNetPearls(http://www.dotnetperls.com/using-alias)中的优点和缺点。

答案 7 :(得分:8)

只是添加一些令我惊讶的东西没有出现。使用(在我看来)最有趣的特点是,无论你如何退出使用块,它总是会处置对象。这包括退货和例外。

using (var db = new DbContext())
{
    if(db.State == State.Closed) throw new Exception("Database connection is closed.");
    return db.Something.ToList();
}

抛出异常或返回列表无关紧要。 DbContext对象将始终处理。

答案 8 :(得分:6)

使用的另一个重要用途是在实例化模态对话框时。

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using

答案 9 :(得分:5)

总之,当您使用实现IDisposable的类型的局部变量时,总是,毫无例外地使用using 1

如果您使用非本地IDisposable变量,则始终实施IDisposable pattern

两个简单的规则,没有例外 1 。否则,防止资源泄漏是* ss的真正痛苦。


1):唯一的例外是 - 当您处理异常时。因此,在Dispose块中明确调用finally可能会减少代码。

答案 10 :(得分:4)

有趣的是,您还可以将using / IDisposable模式用于其他有趣的事情(例如Rhino Mocks使用它的另一个方面)。基本上,您可以利用编译器始终调用.dispose对“used”对象这一事实。如果你有某些东西需要在某个操作之后发生......那些有明确开始和结束的东西......那么你可以简单地创建一个IDisposable类来在构造函数中启动操作,然后在Dispose方法中完成。

这允许您使用非常好的using语法来表示所述操作的显式开始和结束。这也是System.Transactions的工作原理。

答案 11 :(得分:4)

您可以通过以下示例使用别名命名空间:

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;

这被称为使用别名指令,如您所见,它可以用于隐藏冗长的引用,如果您想在代码中明确指出您所指的是什么 e.g。

LegacyEntities.Account

而不是

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

或只是

Account   // It is not obvious this is a legacy entity

答案 12 :(得分:3)

“using”也可用于解决名称空间冲突。有关我就此主题撰写的简短教程,请参阅http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/

答案 13 :(得分:3)

使用ADO.NET时,您可以使用关键字来处理连接对象或读取器对象。这样,当代码块完成时,它将自动处理您的连接。

答案 14 :(得分:3)

public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}

public void fn_Data()

    {
     using (ClassA ObjectName = new ClassA())
            {
                //use objectName 
            }
    }

答案 15 :(得分:1)

它也可用于为示例创建范围:

class LoggerScope:IDisposable {
   static ThreadLocal<LoggerScope> threadScope = 
        new ThreadLocal<LoggerScope>();
   private LoggerScope previous;

   public static LoggerScope Current=> threadScope.Value;

   public bool WithTime{get;}

   public LoggerScope(bool withTime){
       previous = threadScope.Value;
       threadScope.Value = this;
       WithTime=withTime;
   }

   public void Dispose(){
       threadScope.Value = previous;
   }
}


class Program {
   public static void Main(params string[] args){
       new Program().Run();
   }

   public void Run(){
      log("something happend!");
      using(new LoggerScope(false)){
          log("the quick brown fox jumps over the lazy dog!");
          using(new LoggerScope(true)){
              log("nested scope!");
          }
      }
   }

   void log(string message){
      if(LoggerScope.Current!=null){
          Console.WriteLine(message);
          if(LoggerScope.Current.WithTime){
             Console.WriteLine(DateTime.Now);
          }
      }
   }

}

答案 16 :(得分:1)

C#中使用关键字use的两种用法如下。

  1. 作为指令

通常,我们使用using关键字在代码隐藏文件和类文件中添加名称空间。然后,它使当前页面中的所有类,接口和抽象类以及它们的方法和属性可用。

例如:

    string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";  

using (SqlConnection conn = new SqlConnection(connString))  
{  
      SqlCommand cmd = conn.CreateCommand();  
      cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";  
      conn.Open();  
      using (SqlDataReader dr = cmd.ExecuteReader())  
      {  
         while (dr.Read())  
         Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));  
      }  
}  
  1. 作为声明

这是在C#中使用using关键字的另一种方法。它在提高垃圾收集的性能方面起着至关重要的作用。 using语句确保即使在创建对象以及调用方法,属性等时发生异常,也将调用Dispose()。 Dispose()是IDisposable接口中提供的一种方法,可帮助实现自定义垃圾收集。换句话说,如果我正在执行某些数据库操作(“插入”,“更新”,“删除”),但由于某种原因发生了异常,则在这里using语句会自动关闭连接。无需显式调用连接Close()方法。

另一个重要因素是它有助于连接池。 .NET中的连接池有助于避免多次关闭数据库连接。它将连接对象发送到池中以备将来使用(下一次数据库调用)。下次从应用程序中调用数据库连接时,连接池将提取池中可用的对象。因此,它有助于提高应用程序的性能。因此,当我们使用using语句时,控制器将对象自动发送到连接池,无需显式调用Close()和Dispose()方法。

您可以通过使用try-catch块并在finally块内显式调用Dispose()来实现与using语句相同的操作。但是using语句会自动执行调用,以使代码更整洁和美观。在using块中,该对象为只读对象,无法修改或重新分配。

例如:

       [requestURL setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

在前面的代码中,我没有关闭任何连接,它将自动关闭。由于using语句(using(SqlConnection conn = new SqlConnection(connString))和SqlDataReader对象相同,因此using语句将自动调用conn.Close()。如果发生任何异常,它将自动关闭连接。 / p>

有关更多信息-> https://www.c-sharpcorner.com/UploadFile/manas1/usage-and-importance-of-using-in-C-Sharp472/

答案 17 :(得分:1)

using语句告诉.NET在不再需要时释放using块中指定的对象。 所以你应该对需要清理的类使用'using'块,比如System.IO Types。

答案 18 :(得分:1)

对我来说,“使用”这个名字有点令人困惑,因为它可以是一个指令来导入一个命名空间或一个语句(就像这里讨论的那样)来进行错误处理。

错误处理的另一个名称会很好,也许是一个更明显的名称。

答案 19 :(得分:1)

using语句提供了一种方便的机制来正确使用IDisposable对象。通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它。 using语句以正确的方式调用对象上的Dispose方法,并且(如前所示使用它时)一旦调用Dispose,它也会导致对象本身超出范围。在using块中,该对象是只读的,不能修改或重新分配。

这来自:here

答案 20 :(得分:1)

大括号外的所有东西都被处理掉了,所以如果不使用它们,最好处置它们。这是因为如果你有一个SqlDataAdapter对象并且你只在应用程序生命周期中使用它一次并且你只填充一个数据集而你不再需要它,你可以使用代码:

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically

答案 21 :(得分:1)

合理使用的另一个例子,其中立即处理对象:

using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString)) 
{
    while (myReader.Read()) 
    {
        MyObject theObject = new MyObject();
        theObject.PublicProperty = myReader.GetString(0);
        myCollection.Add(theObject);
    }
}

答案 22 :(得分:1)

并非它非常重要,但使用也可用于动态更改资源。如前所述,是可丢弃的,但也许具体地说,您不希望在执行的其余部分中它们与其他资源不匹配的资源。因此,您希望将其丢弃,以免干扰其他地方。

答案 23 :(得分:1)

使用,如果您在使用资源后需要处理它,则会使用

例如,如果您分配了一个文件资源,并且只需要在一段代码中使用它来进行一些读取或写入,那么使用它有助于在完成后立即处理文件资源。

正在使用的资源需要实现IDisposable才能正常工作。

示例:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}

答案 24 :(得分:1)

using关键字定义对象的范围,然后在范围完成时处理对象。例如。

using (Font font2 = new Font("Arial", 10.0f))
{
    // use font2
}

有关C#使用关键字的MSDN文章,请参阅here

答案 25 :(得分:1)

感谢下面的评论,我会稍微清理一下这篇文章(我当时不应该使用'垃圾收集'这个词,道歉):
当您使用using时,它将在使用范围的末尾调用对象上的Dispose()方法。因此,您可以在Dispose()方法中获得相当多的清理代码。
这里的一个要点有望得到这个非标记:如果你实现了IDisposable,请确保你在Dispose()实现中调用GC.SuppressFinalize(),否则自动垃圾收集会尝试出现并在某些时候完成它如果你已经Dispose()d,那至少会浪费资源。

答案 26 :(得分:1)

Rhino Mocks Record-playback Syntaxusing进行了有趣的使用。

答案 27 :(得分:-1)

  

使用as语句自动调用指定的dispose   宾语。该对象必须实现IDisposable接口。它是   可以在一个语句中使用多个对象,只要它们是   相同类型。

CLR将您的代码转换为MSIL。而using语句被转换为try和finally块。这就是在IL中表示using语句的方式。使用声明分为三个部分:获取,使用和处置。首先获取资源,然后将使用情况包含在带有finally子句的try语句中。然后该对象将被置于finally子句中。

答案 28 :(得分:-2)

使用Clause用于定义特定变量的范围。 例如:

     Using(SqlConnection conn=new SqlConnection(ConnectionString)
            {
                Conn.Open()
            // Execute sql statements here.
           // You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
            }