题
这个问题在这里已经有答案了:
- C#中的“using”有什么用 29 个答案
是否存在我应该(或不应该?)使用“using”块的特定情况:
using(SomeType t = new SomeType()){
...
}
解决方案
当。。。的时候 SomeType
类工具 IDisposable
.
其他提示
有些对象在使用完后需要执行一些操作。通常这是因为该对象使用了某种需要处置的资源。例如,如果您有一个 File 类的文件对象,并且该对象从文件系统中打开一个文件,则需要再次关闭文件系统中的文件。
如果您刚刚离开文件对象,并且忘记调用 file.Close(),则直到垃圾收集器 (GC) 运行并发现没有任何东西仍在使用文件对象时,它才会被清理。垃圾收集器何时运行应由公共语言运行时 (CLR) 来决定。如果在处理完文件后 GC 很长一段时间没有运行,则该文件可能会长时间保持打开状态。如果有很多文件对象,或者有些东西想要打开一个文件,但由于您留下的文件对象仍然悬而未决而无法打开,这可能会造成一个大问题。
为了解决这个问题,C#提供了IDisposable接口。它有一种称为 Dispose 的方法。需要一些清理的类实现此 Dispose 方法。这为您提供了清理任何使用资源的对象的标准方法。有很多类需要调用 Dispose。这样做的问题是,代码被对 Dispose 的调用覆盖,并且它们很难跟踪,因为您新建对象和调用 Dispose 来清理它的位置是不同的。因此,您必须仔细查看代码并非常小心地检查是否在正确的位置调用了 Dispose。
为了解决这个问题,C# 引入了“using”关键字。您可以在新建对象的地方放置一个“using”关键字,这可以确保为您调用 Dispose。它保证无论发生什么情况都会调用 Dispose...即使 using 语句体内抛出异常。
因此,当您想要确保分配资源的对象将被清理时,您应该使用“using”。
using 只能用于在堆栈上声明的对象,即在一个函数中。它不适用于声明为类成员的对象。对于它们,您必须自己调用 Dispose。您可能必须在类中实现 Dispose,以便可以在需要它的任何成员对象上调用 Dispose。
需要调用它们的常见对象有:文件、数据库连接、图形对象,例如笔和画笔。
有时,当您希望两个操作同时发生时也可以使用它。例如,如果您想在输入代码块和退出代码块时编写日志语句,您可以编写一个日志类,如下所示:
using( Log log = new Log("Doing stuff") )
{
// Stuff
}
可以使日志类的构造函数写出消息,并且 Dispose 方法也可以将其写出。实现终结器 (~Log) 以在未调用 Dispose 方法时断言,以确保在“新日志”周围记住“使用”。
使用 using
每当类型实现 IDisposable
, ,除非你要把它包裹在一个 try
/catch
无论如何阻止,那么你也可以(取决于你喜欢什么外观)使用 finally
堵塞。
当你看到很多其他答案时 应该 有一个 using
陈述。我想具体说明什么时候应该 不是 有一个 using
陈述:
如果您需要在当前函数的范围之外使用对象,则不要使用 using
堵塞。很好的例子是返回数据库连接的工厂方法或需要返回数据读取器的方法。在这两种情况下,如果您使用 using
声明它将在方法返回之前被释放,因此在方法之外不可用。
现在,你还想成为 当然 这些对象已被处置,所以您可能仍然需要 using
某处声明。只是不要将其包含在实际创建对象的方法中。相反,您可以将函数调用本身包装在 using
陈述。
当 SomeType 实现 IDisposable 时。
对于开发人员来说,这是一个线索,表明 SomeType 使用需要清理的非托管资源。
例子:
using(SqlConnection MyConnection = new SqlConnection("Connection string"))
{
MyConnection.Open();
//...
// 1. SQLConnection is a type that implements IDisposable
// 2. So you can use MyConnection in a using statement
// 3. When using block finishes, it calls Dispose method of
// SqlConnection class
// 4. In this case, it will probably close the connection to
// the database and dispose MyConnection object
}
您可以创建自己的实现 IDisposable 的对象:
public class MyOwnObjectThatImplementsIDisposable : IDisposable
{
//... some code
public void Dispose()
{
// Put here the code you want to be executed when the
// using statement finish.
}
}
因此,您可以在 using 语句中使用 MyOwnObjectThanImplementsIDisposable 类型的对象:
using(MyOwnObjectThatImplementsIDisposable MyObject = new MyOwnObjectThatImplementsIDisposable)
{
// When the statement finishes, it calls the
// code you´ve writed in Dispose method
// of MyOwnObjectThatImplementsIDisposable class
}
希望这可以帮助
在此背景下 using
语句对于实现 IDisposable 的类型很方便。当代码块退出作用域时 using
陈述, Dispose()
被隐式调用。当您处理使用后要立即处理的物品时,这是一个好习惯。
在一个特定的实例中,您应该小心使用 using
块是 使用 WCF 服务客户端.
如中所述 这篇 MSDN 文章, ,包装一个 WCF 客户端(它确实实现了 IDisposable
) 在一个 using
块可以掩盖导致客户端处于故障状态(例如超时或通信问题)的任何错误。长话短说,当 Dispose()
被称为,客户的 Close()
方法会触发,但会抛出错误,因为它处于错误状态。然后,原始异常被第二个异常掩盖。不好。
有多种解决方法,包括 MSDN 文章本身中的一种。其他可以在以下位置找到 面向服务 和 博客.davidbarret.net.
我自己更喜欢最后一种方法。
如果你想要一个总结规则。任何时候当一个对象使用 IDisposable 而你不会有任何捕获时,请使用 using。本质上,使用的是这种模式:
try
{
//instantiate and use object
}
finally
{
//dispose object
}
如果你不需要 catch,使用可以节省你的打字时间,这是一件好事。
主要规则是:* 当对象实现IDisposable接口时使用USING语句。
该接口提供了 Dispose 方法,该方法应该释放对象的资源。如果不调用此方法,则该对象将在内存中保留很长时间,因为 CLR 想要执行垃圾收集。如果程序员使用 USING 语句,那么最终该对象将被释放,并且所有资源将被释放。
尽快释放所有不再使用的资源非常重要。
有关它的更多信息,请访问此链接: 微软
也许值得一提的是,在 C# 语言中添加“using”的根本原因如下:有些资源可能非常稀缺,等待 GC 调用 IDisposable 是没有意义的。例如,数据库连接。如果您使用 try/catch/finally,您不会最终得到悬空连接,但连接将保持挂起状态,直到 GC 不启动为止,这可能需要一段时间(如果您不显式关闭它)。如果您使用“using”(请原谅双关语),即使您忘记关闭它,即使 using 块内发生了一些异常,您也会立即释放连接。
正如前一篇文章提到的,另一个原因是程序员并不总是使用finally来进行清理。如果在异常情况下不使用finally,你最终会泄漏资源......
一种情况是当您想要在代码块的开头执行某些操作,然后在代码块的末尾无条件地撤消它(即使存在抛出)。
您构建(并在 using 中调用)的一次性类的构造函数将执行该操作,然后 Dispose 方法将撤消该操作。这就是我通常使用它的方式。
其他人已经提到过“IDisposable”。
但是,使用“使用”陈述时的警告之一是,在“使用”内部抛出的任何例外都不会被认为是“某些人”,无论如何都会被处置。
所以在下面的片段中,
using (SomeType t = new SomeType()){
throw new Exception("thrown within using");
}
throw new Exception("thrown within using");
不应被忽视。
我还要补充一点,使用 using()
声明如果有东西实现 IDispose
另外,如果您想要处理保留非托管资源(例如数据库连接和文件句柄)的内容。
如果它是一个普通物体,比如 List<T>
, ,其中 T 就像 Customer
持有姓名和地址的对象,那么你就不需要了。垃圾收集器足够聪明,可以为您管理此操作。但垃圾收集器不会将连接返回到连接池或关闭文件句柄。