处理IDisposable对象的通用函数

Jer*_*ing 11 c# generics idisposable

我正在处理一个处理大量Sql对象的类 - 连接,命令,DataAdapter,CommandBuilder等.有多个实例我们有这样的代码:

if( command != null )
{
    command.Dispose();
}

if( dataAdapter != null )
{
    dataAdapter.Dispose();
}

etc
Run Code Online (Sandbox Code Playgroud)

我知道这在重复方面相当不足,但它已经开始闻起来了.我认为它闻起来的原因是因为在某些情况下该对象也被设置为null.

if( command != null )
{
    command.Dispose();
    command = null;
}
Run Code Online (Sandbox Code Playgroud)

如果可能的话,我希望摆脱重复.我已经提出了这种通用方法来处理一个对象并将其设置为null.

private void DisposeObject<TDisposable>( ref TDisposable disposableObject )
    where TDisposable : class, IDisposable
{
    if( disposableObject != null )
    {
        disposableObject.Dispose();
        disposableObject = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是......

  1. 这个通用功能是个坏主意吗?
  2. 是否有必要将对象设置为null

编辑:

我知道这个using声明,但是我不能总是使用它,因为我有一些成员变量需要持续超过一次调用.例如,连接和事务对象.

谢谢!

Mar*_*ers 7

您应该考虑是否可以使用该using声明.

using (SqlCommand command = ...)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这可确保Dispose在控件离开使用范围时在命令对象上调用.与您自己编写清理代码相比,这有许多优点:

  • 它更简洁.
  • 该变量永远不会设置为null - 它在一个语句中声明和初始化.
  • 当对象被处置时,变量超出范围,因此您可以降低意外尝试访问已处置资源的风险.
  • 它是例外安全的.
  • 如果使用语句进行嵌套,则资源自然按正确的顺序排列(与创建它们的顺序相反).

是否有必要将对象设置为null?

完成使用后,通常不需要将变量设置为null.重要的是,在使用完资源后调用Dispose.如果使用上述模式,则不仅不必将变量设置为null - 它将产生编译错误:

Cannot assign to 'c' because it is a 'using variable'

需要注意的一点是,using只有在同一方法调用中获取并处理对象时才有效.如果您的资源需要在多个方法调用期间保持活动状态,则无法使用此模式.在这种情况下,您可能希望使类实现IDisposable并确保在调用Dispose方法时清理资源.在这种情况下,您将需要像您所写的代码.null在这种情况下将变量设置为没有错,但这并不重要,因为垃圾收集器无论如何都会正确地清理内存.重要的是确保在调用dispose方法时处置您拥有的所有资源,并且您正在这样做.

一些实现细节:

  • 你应该确保如果你的Dispose被调用两次,它就不会抛出异常.您的实用程序功能正确处理此案例.
  • ObjectDisposedException如果对象已被处置,则应确保对象上的相关方法引发.


Ste*_*ary 6

您应该IDisposable在拥有这些字段的类中实现.请参阅关于此主题的博客文章.如果这不能很好地工作,那么该类不遵循OOP原则,需要重构.

这是没有必要的变量设置为null处置他们了.


Tim*_*son 1

我假设这些是字段而不是局部变量,因此关键字using没有意义。

这个通用函数是一个坏主意吗?

我认为这是一个好主意,并且我已经使用过几次类似的功能;+1使其通用。

是否需要将对象设置为null?

从技术上讲,一个对象应该允许对其Dispose方法进行多次调用。(例如,如果一个对象在终结过程中复活,就会发生这种情况。)在实践中,这取决于您是否信任这些类的作者或者是否想要防御性地编码。就我个人而言,我检查 null,然后将引用设置为 null。

编辑:如果此代码位于您自己的对象的Dispose方法内,则未能将引用设置为 null 不会泄漏内存。相反,它可以方便地防御双重处置。