在C#中使用“using”

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

“使用”语句的原因是为了确保对象在超出作用域时尽快处理,并且不需要显式代码来确保这种情况发生。

按照http://www.codeproject.com/KB/cs/ extinguusingstatement.aspx ,.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(); } } 

由于很多人还在做:

 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 } 

像这样的事情:

 using (var conn = new SqlConnection("connection string")) { conn.Open(); // execute sql statement here on the connection you created } 

这个SqlConnection将被closures,而不需要显式地调用.Close()函数, 即使抛出一个exception也不会发生这种情况,而不需要try / catch / finally。

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

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

在…的意义上使用

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

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

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

当然,您会注意到,第一个代码片段比第二个代码片段更加简洁,即使发生exception,您也可能需要执行许多种类的操作。 因此,我们想出了一个叫做Scope的类,允许你在Dispose方法中执行任意代码。 因此,例如,如果您有一个名为IsWorking的属性,在尝试执行操作之后,您总是希望将其设置为false,则可以这样做:

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

你可以阅读更多关于我们的解决scheme,以及我们如何在这里得出它

过去我曾经使用它来处理input和输出stream。 你可以把它们很好地嵌套在一起,它通常会带走很多潜在的问题(通过自动调用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(); } } } 

Microsoft文档指出, 使用具有双重function( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ),作为指令语句 。 作为一个声明 ,正如在其他答案中指出的那样,关键字基本上是语法糖来决定一个范围来configuration一个IDisposable对象。 作为指令 ,它通常用于导入名称空间和types。 也作为指令,您可以为名称空间和types创build别名 ,正如“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; } } } 

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

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

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

抛出exception或返回列表无关紧要。 DbContext对象将始终处置。

使用另一个很好的用途是实例化一个modal dialog。

使用frm作为新的Form1

Form1.ShowDialog

'在这里做东西'

结束使用“

有趣的是,你也可以使用use / IDisposable模式来处理其他有趣的事情(比如Rhino Mocks使用它的另一个方面)。 基本上,你可以利用编译器总是调用.Dispose在“used”对象上的事实。 如果在某个操作之后有某些事情需要发生,那么就有一个确定的开始和结束的事情,那么你可以简单地创build一个IDisposable类来启动构造函数中的操作,然后在Dispose方法中完成。

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

总之,当你使用一个实现了IDisposable的types的局部variables时, 总是毫无例外地using 1

如果使用非本地IDisposablevariables,则始终实现IDisposable模式 。

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


1) :唯一的例外是 – 当你处理exception。 那么在finally块中显式调用Dispose代码可能会less一些。

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

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

这就是所谓的使用别名指令 ,正如你所看到的,它可以用来隐藏冗长的引用,如果你想在你的代码中显而易见你所指的是

 LegacyEntities.Account 

代替

 CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account 

或干脆

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

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

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

RhinoMocks使用一个intersting使用。

当你有一个你想要使用的资源时, 使用using

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

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

例:

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

using关键字定义对象的作用域,然后在作用域完成时将对象处置掉。 例如。

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

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

不是说这是非常重要的,但是使用也可以用来改变资源。 如前所述,是一次性的,但也许特别是你不希望在执行的其余部分期间与其他资源不匹配的资源。 所以你想处理它,所以它不会干涉其他地方。

由于下面的评论,我会清理这个post了一些(我不应该在当时使用“垃圾收集”的话,道歉):
当使用using时,它将在使用范围的末尾调用对象上的Dispose()方法。 所以你可以在你的Dispose()方法中有相当多的清理代码。
这里希望可能会得到这个un-downdown的一个要点:如果你实现了IDisposable,确保你在你的Dispose()实现中调用GC.SuppressFinalize(),否则自动垃圾收集将尝试进行,并在一些如果你已经Dispose()d,至less会浪费资源。

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

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

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

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

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

这来自: 这里

对于我来说,名称“using”有点令人困惑,因为可以是一个导入命名空间或语句的指令(就像这里所讨论的)来进行error handling。

error handling的不同名称会很好,也许更明显一些。

它也可以用于创build示例:

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

使用子句用于定义特定variables的范围。 例如:

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