用户kokos通过提及关键字回答了C#问题的精彩隐藏功能using
.你能详细说明吗?有什么用using
?
using
声明的原因是确保对象在超出范围时立即处理,并且不需要显式代码来确保发生这种情况.
与理解C#中的"using"语句一样,.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
将被关闭而无需显式调用该.Close()
函数,即使抛出异常,也会发生这种情况,而不需要try
/ catch
/ finally
.
使用可以用来调用IDisposable.它也可以用于别名类型.
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(); }
当然,您会注意到,第一个代码段比第二个代码段更简洁,并且即使抛出异常,您也可能需要执行许多类型的事务清理.因此,我们提出了一个我们称之为Scope的类,它允许您在Dispose方法中执行任意代码.因此,例如,如果您有一个名为IsWorking的属性,您在尝试执行操作后总是想要设置为false,那么您可以这样做:
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).一个例子:
namespace HelloWorld { using AppFunc = Func, List >; public class Startup { public static AppFunc OrderEvents() { AppFunc appFunc = (IDictionary events) => { if ((events != null) && (events.Count > 0)) { List 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).例如:
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(); } } }
只是添加一些我感到惊讶的东西没有出现.使用(在我看来)最有趣的特点是,无论你如何退出使用块,它总是会处置对象.这包括退货和例外.
using (var db = new DbContext()) { if(db.State == State.Closed) throw new Exception("Database connection is closed."); return db.Something.ToList(); }
抛出异常或返回列表无关紧要.将始终处理DbContext对象.
使用的另一个重要用途是在实例化模态对话框时.
Using frm as new Form1 Form1.ShowDialog ' do stuff here End Using
总之,当您使用实现的类型的局部变量时IDisposable
,始终无一例外地使用using
1。
如果您使用非局部IDisposable
变量,请务必实施IDisposable
pattern。
两个简单的规则,也不例外1。否则,防止资源泄漏是* ss的真正痛苦。
1):唯一的例外是–处理例外时。这样,Dispose
在该finally
块中显式调用的代码可能会更少。
您可以通过以下示例使用别名名称空间:
using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;
如您所见,这被称为using别名指令,如果您想在代码中使其变得显而易见,则可以将其用于隐藏长引用,例如
LegacyEntities.Account
代替
CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account
或简单地
Account // It is not obvious this is a legacy entity