我对C#还比较陌生,更习惯于脚本语言。但我喜欢“using”的思想:你实例化一个对象,然后在需要它的范围内操作,完成后就让它自动清理。
然而,这对我来说并不是那么自然。当别人用它给我展示一些例子时,我认为这是一个好工具,但在自己的编程中从未考虑过使用它来解决问题。
我应该如何识别使用using
的好地方,以及如何与try-catch块结合使用?它们是否应该放在块内部,或者通常需要将using语句包含在try块内?
我对C#还比较陌生,更习惯于脚本语言。但我喜欢“using”的思想:你实例化一个对象,然后在需要它的范围内操作,完成后就让它自动清理。
然而,这对我来说并不是那么自然。当别人用它给我展示一些例子时,我认为这是一个好工具,但在自己的编程中从未考虑过使用它来解决问题。
我应该如何识别使用using
的好地方,以及如何与try-catch块结合使用?它们是否应该放在块内部,或者通常需要将using语句包含在try块内?
using
只能用于实现了IDisposable
接口的类型;它保证即使发生错误,也会调用Dispose()
方法。
以下代码:
using (MyDisposableType x = new MyDisposableType())
{
// use x
}
等同于这个:
MyDisposableType x = new MyDisposableType();
try
{
// use x
}
finally
{
x.Dispose();
}
我曾经认为它的意思是“每当使用实现IDisposable接口的类型时,如果你不再需要这个特定的实例,就使用它”。
try
/finally
或 using
可以帮助您的情况。try
/finally
或 using
。IDisposable
的类来捕获该模式,并使用 using
语句调用该模式。但如果您有一个特定的只出现一次的情况,那么就只需使用 try
/finally
。using
是基于 try
/finally
指定的,但即使我们只有 using
,也可以自己构建 try
/finally
:public class DisposeAnything : IDisposable
{
public Action Disposer;
public void Dispose()
{
Disposer();
}
}
现在你可以说:
using (new DisposeAnything
{
Disposer = () => File.Delete(tempFileName)
})
{
// blah
}
这与以下内容相同:
try
{
// blah
}
finally
{
File.Delete(tempFileName);
}
可以将其视为在离开作用域时执行一些代码的方法。
当您需要确定性对象处理时,请使用using。例如,如果您打开一个文件,则该文件将被锁定。您通常希望尽快关闭文件,以便其他程序可以访问它。如果您不使用using并编写类似以下内容的代码:
System.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) );
System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) );
//do smth
当“做某事”期间发生异常时,您不知道在何时对象操作文件被实际处置并关闭文件。使用 using,您可以确定一旦离开 using 语句块 - 直接或通过异常 - 在 using 语句中的对象将通过调用 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
}
}
你可以在 try/catch 块内部包含 using,也可以在 using 内部包含 try/catch 块。
使用 using 的一个好处是在使用 DBConnection 和 DBCommands 进行数据库操作时:
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sql, conn))
{
// do something here
}
米奇说得没错。使用 using 的主要目的是确保 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.
除了Mitch说的之外...
您可以在try..catch块内部或外部使用using语句,这取决于您想要实现的目标,例如是否合理地期望某些内容在使用特定对象时引发异常并计划从中恢复。
同样,如果需要,您也可以在finally块中处理实现IDisposable接口的对象的Dispose方法。
鉴于它被称为“语法糖”,并且将生成与try/finally dispose结构相同的IL,因此它实际上只是一种优雅的方式来“简写”这样的代码。
我喜欢在使用可处理对象的代码段(例如访问文件和图形对象等资源)时使用它来简化代码,并确保我不会忘记处理资源对象的释放。