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

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

What are the uses of “using” in C#

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


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

与理解C#中的"using"语句一样,.NET CLR也会转换

1
2
3
4
using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ // 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
2
3
4
using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

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

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

这样的事情:

1
2
3
4
5
6
using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

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

这个SqlConnection将被关闭,而不需要显式调用.Close()函数,即使抛出异常,也会发生这种情况,而不需要try / catch / finally


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

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


使用,在...的意义上

1
2
3
4
using (var foo = new Bar())
{
  Baz();
}

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

1
2
3
4
5
6
7
8
9
var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

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

1
2
3
4
5
using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

您可以在此处详细了解我们的解决方案及其衍生方式。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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#别名有一个很好的解释,也提到了优点和缺点。


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

1
2
3
4
5
6
7
8
9
10
        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();
                }
            }
        }

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

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

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


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

1
2
3
4
5
6
7
Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using


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

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

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

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


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

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

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

1
LegacyEntities.Account

代替

1
CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

或者干脆

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

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

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


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


"using"也可用于解决名称空间冲突。有关我在这个主题上写的简短教程,请参见http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/。


1
2
3
4
5
6
7
8
9
10
public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}
1
2
3
4
5
6
7
8
public void fn_Data()

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

当您拥有在使用之后要处置的资源时,将使用"使用"。

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

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

例:

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

Rhino Mocks记录播放语法对using进行了有趣的使用。


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


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


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

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

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


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

1
2
3
4
5
6
7
8
9
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);
    }
}

对我来说,名称"使用"有点令人困惑,因为它可以是一个指令,用于导入命名空间或语句(如此处讨论的那样)以进行错误处理。

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


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


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

这来自:这里


在C#中使用关键字有两种用法,如下所示。

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

    例如:

    1
    using System.IO;
  • 作为声明
  • 这是在C#中使用using关键字的另一种方法。它在提高垃圾收集性能方面起着至关重要的作用。
    using语句确保即使在创建对象和调用方法,属性等时发生异常,也会调用Dispose()。 Dispose()是一种存在于IDisposable接口中的方法,有助于实现自定义垃圾收集。换句话说,如果我正在进行一些数据库操作(插入,更新,删除)但不知何故发生异常,那么using语句会自动关闭连接。无需显式调用连接Close()方法。

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

    你可以使用try-catch块和using语句执行的操作相同,并显式调用finally块中的Dispose()。但using语句会自动调用以使代码更清晰,更优雅。在using块中,该对象是只读的,不能修改或重新分配。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        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语句将由于using语句(使用(SqlConnection conn = new SqlConnection(connString))而自动调用conn.Close(),对于SqlDataReader对象也是如此。如果发生任何异常,它将自动关闭连接。

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


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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    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);
              }
          }
       }

    }

    using as a statement automatically calls the dispose on the specified
    object. The object must implement the IDisposable interface. It is
    possible to use several objects in one statement as long as they are
    of the same type.

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


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

    1
    2
    3
    4
    5
    6
         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.
                }

    推荐阅读