“using”的用法是什么?在c#中?

310992 次浏览

当使用ADO时。NET中,你可以在connection对象或reader对象上使用keywork。这样,当代码块完成时,它将自动处理您的连接。

比如:

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


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

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

Rhino模拟记录回放语法using进行了有趣的使用。

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

要点:

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

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

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

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

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

使用关键字定义对象的作用域,然后在作用域完成时释放对象。为例。

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

有关c# 使用关键字的MSDN文章,请参阅在这里

使用用于当你有一个资源,你想在它被使用后释放它。

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

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

例子:

using (File file = new File (parameters))
{
// Code to do stuff with the file
}

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

就像在理解c#中的" using "语句(codeproject)使用实现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声明是一个前面有using关键字的变量声明。它告诉编译器,所声明的变量应该在封闭作用域的末尾被处理。

所以上面的等效代码是:

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

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

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

这允许您使用非常好的使用语法来指示所述操作的显式开始和结束。这也是系统如何。事务处理可以工作。

在过去,我经常使用它来处理输入和输出流。您可以很好地嵌套它们,这消除了您通常遇到的许多潜在问题(通过自动调用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 (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
}

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

如果使用非本地的IDisposable变量,则总是实现IDisposable模式. 0。

两个简单的规则,没有例外__abc0。否则,防止资源泄漏是一件非常痛苦的事情。


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

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

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 frm as new Form1


Form1.ShowDialog


' Do stuff here


End Using

使用,在意义上

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

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

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

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

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

你可以阅读更多关于我们的解决方案和我们如何推导它在这里

大括号之外的所有内容都将被处理,因此如果您不使用对象,则可以对它们进行处理。这是因为如果你有一个SqlDataAdapter对象,你在应用程序生命周期中只使用它一次,你只填充一个数据集,你不再需要它,你可以使用以下代码:

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
// do stuff
} // here adapter_object is disposed automatically
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
}
}

使用子句用于定义特定变量的作用域。

例如:

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

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

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;
如你所见,这被称为使用别名指令,它可以用来隐藏冗长的引用,如果你想在你的代码中明显地显示你所引用的内容 例如< / p >
LegacyEntities.Account

而不是

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

或者简单地

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

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

使用语句以正确的方式调用对象上的Dispose方法,并且(当您像前面所示那样使用它时)它还会导致对象本身在Dispose被调用时超出作用域。在使用块中,对象是只读的,不能被修改或重新分配。

它来自在这里

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

为错误处理取一个不同的名字会很好,而且可能是一个更明显的名字。

只是添加了一点我很惊讶没有出现的东西。使用最有趣的特性(在我看来)是无论你如何退出使用块,它总是会释放对象。这包括返回和异常。

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

这与是否抛出异常或是否返回列表无关。DbContext对象总是会被释放。

微软文档指出使用有一个双重函数(https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx),既作为指令,也在语句中。作为声明,正如这里在其他回答中指出的那样,关键字基本上是语法糖,用于确定处理IDisposable对象的作用域。作为指令,它通常用于导入名称空间和类型。同样作为一个指令,你可以为命名空间和类型创建别名,正如Joseph和Ben Albahari在《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#别名的很好的解释,也提到了优点和缺点。

它也可以用于创建作用域,例如:

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


}

使用语句告诉. net一旦不再需要使用块中指定的对象,就释放它。

所以你应该使用'using'块来处理那些需要在它们之后清理的类,比如系统。IO类型。

using as语句自动调用指定的dispose函数 对象。对象必须实现IDisposable接口。它是 可以在一条语句中使用多个对象,只要它们是

CLR将你的代码转换为CIL使用语句被转换为try和finally语句块。这就是使用语句在CIL中的表示方式。使用语句被翻译成三个部分:获取、使用和处置。首先获取资源,然后使用最后子句括在试一试语句中。对象然后在最后子句中被释放。

在c#中using关键字有以下两种用法。

  1. 作为指令

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

    例子:

    using System.IO;
    
  2. 作为一个语句

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

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

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

    你可以像using语句一样使用try-catch块,并显式地调用finally块中的Dispose()。但是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语句(using (SqlConnection conn = new SqlConnection(connString)), using语句将自动调用conn.Close(),对于SqlDataReader对象也是如此。并且如果发生任何异常,它将自动关闭连接。

更多信息,参见 c#中使用的用法和重要性