我怎么知道使用'使用'的最佳地点?

时间:2009-04-03 07:06:19

标签: c# using-statement

我对c#有点新手,更习惯于编写脚本语言。我喜欢'使用'的想法,你实例化一个对象,然后只要你需要它就在它的范围内运行,然后当它完成它的目的时你让它自己处理掉。

但是,这对我来说并不自然。当人们向我展示使用它的例子时,我认为它是一个很好的工具,但是在我自己的编程中解决它的问题从来没有发生过。

如何识别使用using的好地方,以及如何将其与try-catch块结合使用。它们是否进入块内,或者您是否通常想在try块中包含using语句?

11 个答案:

答案 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 / finallyusing可以帮助您的情况。

特别是,如果您尝试通过捕获所有异常来实现此目标,那么您必须改为try / finallyusing

如果模式多次出现,您可以创建一个实现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)

当您需要确定性对象处理时,使用使用。例如,如果您打开文件,该文件将被锁定。您通常希望尽快关闭该文件,以便其他程序可以访问它。如果您不使用使用并编写类似:

的smth
System.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方法中有代码 - 所以总是调用它。