我对c#有点新手,更习惯于编写脚本语言。我喜欢'使用'的想法,你实例化一个对象,然后只要你需要它就在它的范围内运行,然后当它完成它的目的时你让它自己处理掉。
但是,这对我来说并不自然。当人们向我展示使用它的例子时,我认为它是一个很好的工具,但是在我自己的编程中解决它的问题从来没有发生过。
如何识别使用using
的好地方,以及如何将其与try-catch块结合使用。它们是否进入块内,或者您是否通常想在try块中包含using语句?
答案 0 :(得分:18)
using
只能与实施IDisposable
的类型一起使用;它保证即使发生错误也会调用Dispose()
方法。
此代码:
using (MyDisposableType x = new MyDisposableType())
{
// use x
}
相当于:
MyDisposableType x = new MyDisposableType();
try
{
// use x
}
finally
{
x.Dispose();
}
答案 1 :(得分:9)
我很少编写try / catch块 - 大多数异常会被抛到(靠近)堆栈的顶部。如果我做需要一个try / catch块,我不确定我将它放在using
语句与外部之间是否特别一致。这实际上取决于您是否希望在运行异常处理代码之前处置资源。
如果你问何时你应该写using
语句 - 任何时候你“拥有”一个实现IDisposable
的对象(直接或间接通过继承并控制其寿命。这通常是一个使用非托管资源(如文件句柄或网络连接)的对象。它并不总是非常明显,但你通过经验学习。几乎任何与IO有关的都是一次性的,Windows处理(对于字体等)也是类似的。
答案 2 :(得分:3)
我习惯把它想象为“每次类型实现IDisposable时都使用它,而你不再需要这个特定实例”。
答案 3 :(得分:2)
如果您想知道如何在自己的设计中创造性地使用它,请查看一些您自己的代码,以了解在退出封闭块之前必须执行特定代码的情况。这些是try
/ finally
或using
可以帮助您的情况。
特别是,如果您尝试通过捕获所有异常来实现此目标,那么您必须改为try
/ finally
或using
。
如果模式多次出现,您可以创建一个实现IDisposable
的类来捕获模式,并允许您使用using
语句调用模式。但是,如果您的特定案例似乎是一次性的,那么只需使用try
/ finally
。
两者非常相似,实际上 - using
是根据try
/ finally
指定的,但即使我们只有using
,我们也可以构建{{ 1}} / try
我们自己:
finally
现在你可以说:
public class DisposeAnything : IDisposable
{
public Action Disposer;
public void Dispose()
{
Disposer();
}
}
与以下内容相同:
using (new DisposeAnything
{
Disposer = () => File.Delete(tempFileName)
})
{
// blah
}
只需将其视为在离开范围时执行某些代码的方法。
答案 4 :(得分:1)
米奇说,加上..
你可以在try..catch块之外或之内使用using语句,它实际上取决于你想要实现的目标,即你是否合理地期望在使用你计划从中恢复的特定对象时抛出异常,例如。
出于同样的原因,如果需要,你也可以在finally块中处理一个实现IDisposable的对象。
答案 5 :(得分:1)
当您需要确定性对象处理时,使用使用。例如,如果您打开文件,该文件将被锁定。您通常希望尽快关闭该文件,以便其他程序可以访问它。如果您不使用使用并编写类似:
的smthSystem.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) );
System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) );
//do smth
并且在“do smth”期间发生异常,您不知道何时实际处理文件上的对象并关闭文件。使用使用,您可以确定一旦离开使用语句块 - 直接或通过异常,使用语句中的对象是通过调用IDisposable处理:: Dispose:
using( System.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) ) {
using( System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) ) {
//do stmth
}
}
答案 6 :(得分:1)
您可以在try / catch块中包含一个using,并且可以在使用中包含try / catch块。
使用很好的一种情况是使用DBConnection和DBCommands进行数据库操作时:
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sql, conn))
{
// do something here
}
现在,当您离开使用块时,您的命令将被释放并且连接已关闭。
答案 7 :(得分:1)
米奇所说的是对的。所以使用的主要用途是确保IDisposable对象被处理掉,没有必须编写try / catch或try / finally语句。
现在,您可能会发现更高级的用途。当您使用using语句时,编译器会生成一个try / finally,并且它还会在它生成的finally内部为您生成对Dispose()的调用。你可以使用这个Dispose()方法作为“钩子”来做你想做的任何事情......不必与释放资源有关。
例如,Jeffrey Richter在他编写的计时器对象中使用它。你可以用它做这样的事情(仅概念性):
using(var x = new Timer())
{
// Do the operation you want timed
}
// Now, the timer has been stopped, because the
// compiler-generated call to Dispose() has already
// occurred, and Jeffrey uses Dispose() to stop
// the timer.
答案 8 :(得分:1)
如果一个类实现了IDisposable,那可能是有充分理由的。因此,应该处理任何实现IDisposable的类。
答案 9 :(得分:1)
鉴于它是所谓的“语法糖”并且将产生与try / finally dispose构造相同的IL,它实际上只是一种“短处理”这种代码的好方法。
我喜欢用它来简化使用一次性对象的代码段,即访问文件和图形对象等资源,我想确保我不会忘记处理资源对象的处理
答案 10 :(得分:0)
我注意到当Dispose方法已知通知时,程序员不会打扰它,因为它似乎毫无意义。但是,如果对象实现了IDisposable(希望)有一个原因,那个对象的未来版本实际上可能在Dispose方法中有代码 - 所以总是调用它。