339

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

4

29 回答 29

513

using语句的原因是确保对象一旦超出范围就被释放,并且不需要显式代码来确保发生这种情况。

了解 C# (codeproject) 中的 'using' 语句使用实现 IDisposable (microsoft)的对象一样,C# 编译器将

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();
    }
}

C# 8 引入了一种新语法,名为“ using declarations ”:

using 声明是一个以 using 关键字开头的变量声明。它告诉编译器被声明的变量应该放在封闭范围的末尾。

所以上面的等效代码是:

using var myRes = new MyResource();
myRes.DoSomething();

并且当控件离开包含范围(通常是方法,但也可以是代码块)时,myRes将被释放。

于 2008-09-16T18:30:43.673 回答
132

由于很多人仍然这样做:

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
}
于 2008-09-16T19:11:57.927 回答
98

像这样的事情:

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

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

SqlConnection将在不需要显式调用函数的情况下关闭,即使抛出异常.Close()也会发生这种情况,不需要// 。trycatchfinally

于 2008-09-16T18:26:00.860 回答
31

using可用于调用 IDisposable。它也可以用于给类型起别名。

using (SqlConnection cnn = new SqlConnection()) { /* Code */}
using f1 = System.Windows.Forms.Form;
于 2008-09-16T18:26:59.797 回答
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();
}

您可以在此处阅读更多关于我们的解决方案以及我们如何获得它的信息。

于 2008-10-15T14:35:07.530 回答
12

Microsoft 文档指出using具有双重功能 ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ),既可以作为指令,也可以作为语句。作为一个声明,正如在其他答案中指出的那样,关键字基本上是语法糖,用于确定处置IDisposable对象的范围。作为指令,它通常用于导入命名空间和类型。此外,作为指令,您可以为命名空间和类型创建别名,正如“C# 5.0 In a Nutshell: The Definitive Guide”一书中所指出的那样(http://www.amazon.com/5-0-Nutshell-The- Definitive-Reference-ebook/dp/B008E6I1K8),约瑟夫和本阿尔巴哈里。一个例子:

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;
        }
    }
}

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

于 2015-12-25T18:30:24.297 回答
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();
                }
            }
        }
于 2008-09-16T18:34:56.130 回答
8

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

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

抛出异常或返回列表都没有关系。DbContext 对象将始终被释放。

于 2015-04-27T13:46:03.617 回答
6

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

Using frm as new Form1

    Form1.ShowDialog

    ' Do stuff here

End Using
于 2008-09-16T19:58:22.963 回答
5

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

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

如您所见,这称为using alias 指令,如果您想在代码中明确指出您所指的内容,它可用于隐藏冗长的引用,例如

LegacyEntities.Account

代替

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

或者干脆

Account   // It is not obvious this is a legacy entity
于 2014-04-10T17:27:09.330 回答
4

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

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

于 2008-09-16T18:32:18.803 回答
4

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

如果您使用非局部IDisposable变量,则始终实现该IDisposable模式

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


1):唯一的例外是 – 当您处理异常时。然后在块Dispose中显式调用的代码可能会更少。finally

于 2008-09-16T19:48:32.583 回答
3

使用 ADO.NET 时,您可以将密钥用于连接对象或读取器对象等内容。这样,当代码块完成时,它将自动处理您的连接。

于 2008-09-16T18:25:33.017 回答
3

"using" 也可用于解决命名空间冲突。

请参阅http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/了解我写的关于该主题的简短教程。

于 2008-09-16T18:27:30.593 回答
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
    }
}
于 2012-11-01T10:54:37.540 回答
3

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

  1. 作为指令

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

    例子:

    using System.IO;
    
  2. 作为声明

    using这是在 C# 中使用关键字的另一种方式。它在提高垃圾收集性能方面起着至关重要的作用。

    using语句确保即使在创建对象和调用方法、属性等时发生异常,也会调用 Dispose()。Dispose() 是 IDisposable 接口中存在的一种方法,可帮助实现自定义垃圾回收。换句话说,如果我正在执行一些数据库操作(插入、更新、删除)但不知何故发生了异常,那么这里 using 语句会自动关闭连接。无需显式调用连接 Close() 方法。

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

    您可以通过使用 try-catch 块并显式调用 finally 块内的 Dispose() 来执行与 using 语句相同的操作。但是 using 语句会自动执行调用以使代码更简洁、更优雅。在 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));
          }
    }
    

在前面的代码中,我没有关闭任何连接;它会自动关闭。由于语句 ( ),该using语句将自动调用 conn.Close() ,对于 SqlDataReader 对象也是如此。如果发生任何异常,它也会自动关闭连接。usingusing (SqlConnection conn = new SqlConnection(connString)

有关详细信息,请参阅在 C# 中使用的用法和重要性

于 2018-07-30T08:49:03.190 回答
2

using用于当你有一个资源在使用后你想要处理它。

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

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

例子:

using (File file = new File (parameters))
{
    // Code to do stuff with the file
}
于 2008-09-16T18:30:26.077 回答
1

当你使用using时,它会在 using 作用域的末尾调用对象的 Dispose() 方法。所以你可以在你的 Dispose() 方法中有很多很棒的清理代码。

一个要点:

如果您实现 IDisposable,请确保在您的 Dispose() 实现中调用 GC.SuppressFinalize(),否则自动垃圾收集将尝试出现并在某个时候完成它,如果您这样做至少会浪费资源'已经 Dispose()d 了。

于 2008-09-16T18:26:56.210 回答
1

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

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

有关 C# using关键字的 MSDN 文章,请参见此处。

于 2008-09-16T18:28:20.280 回答
1

并不是说它非常重要,但using也可用于动态更改资源。

是的,如前所述是一次性的,但也许特别是您不希望在其余执行期间它们与其他资源不匹配的资源。所以你想处理它,这样它就不会干扰其他地方。

于 2008-09-16T18:47:25.070 回答
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);
    }
}
于 2008-09-16T19:52:49.077 回答
1

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

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically
于 2008-10-15T14:43:26.340 回答
1

using语句提供了一种方便的机制来正确使用 IDisposable 对象。通常,当您使用 IDisposable 对象时,您应该在 using 语句中声明和实例化它。

using语句以正确的方式调用对象的Dispose 方法,并且(当您如前所示使用它时)它还会导致对象本身在调用 Dispose 时立即超出范围。在using块中,对象是只读的,不能修改或重新分配。

这来自这里

于 2015-04-02T07:15:57.473 回答
1

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

错误处理的不同名称会很好,而且可能更明显。

于 2015-04-27T13:33:47.803 回答
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);
          }
      }
   }

}
于 2017-01-04T11:51:52.250 回答
1

using语句告诉 .NET 在不再需要时释放 using 块中指定的对象

因此,您应该将“使用”块用于需要在它们之后清理的类,例如System.IO类型。

于 2018-03-08T06:16:54.400 回答
0

Rhino Mocks Record-playback Syntaxusing.

于 2008-09-16T18:26:38.630 回答
0

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

CLR将您的代码转换为CIL。并且using语句被转换为 try 和 finally 块。这就是using语句在 CIL 中的表示方式。using语句被翻译成三个部分:获取、使用和处置。首先获取资源,然后将使用情况包含在带有finally子句的try语句中。然后对象在finally子句中被释放。

于 2018-05-11T13:16:04.917 回答
-3

using子句用于定义特定变量的范围。

例如:

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 goes out of the defined scope.
}
于 2013-11-28T17:04:58.353 回答