这是IDisposable的正确用法吗?

时间:2013-04-14 01:12:38

标签: c# idisposable

我有一个FTP类,它有一个Dipose()方法

public class Ftp : IFtp
    {
        //other methods, properties and fields

        public void Dispose()
        {
            if (_ftp.IsConnected)
                _ftp.Close();

            _ftp.Dispose();
            _ftp = null;
        }
    }

这是我用来访问Ftp

的界面
public interface IFtp : IDisposable
    {
        //other methods signatures
        void Dispose();
    }

这是处理Ftp使用的内容的正确和功能性方法吗?

3 个答案:

答案 0 :(得分:3)

这适用于经常使用该课程。但是,在开始访问_ftp引用之前,应检查Dispose引用是否为空。通常的做法是,您应该能够多次调用{{1}}方法而不会造成任何伤害。

您可能还想在该类中添加一个Finalizer,如果使用该类的人因某种原因无法正确处理它,您可以将其丢弃。

IDisposable interface文档中的编码示例非常完整且评论很好。

答案 1 :(得分:3)

我认为_ftp是一个IDisposable对象。如果是这样,它应该足以完成以下任务:

public class Ftp : IFtp
{
    //other methods, properties and fields

    public void Dispose()
    {
        _ftp.Dispose();    
    }
}

public interface IFtp : IDisposable
{
    //other methods signatures    
}

也就是说,如果您的接口继承自Dispose(),则无需重新指定IDisposable方法(在您的界面中),因为它已在IDisposable中指定。

答案 2 :(得分:2)

一般参考MSDN documentation for IDisposable interface

MSDN IDisposable.Dispose() documentation具体说明:

  

实施此方法时,请确保所有持有的资源都是   通过包含层次结构传播调用释放。对于   例如,如果对象A分配对象B,则对象B分配   一个对象C,然后A的Dispose实现必须调用B上的Dispose,   必须依次调用Dispose on C。一个对象也必须调用   如果基类实现,则调用其基类的方法   IDisposable的。

......这就是你正在做的事情。

有关设计警告的详细信息,请参阅MSDN CA1063: Implement IDisposable correctly

假设您的基础FTP实现未受管理,那么 还应包含终结器(如果基础实现中尚未存在)。 MSDN IDisposable.Dispose() documentation具体说明:

  

因为必须显式调用Dispose方法,才能调用对象   实现IDisposable还必须实现一个终结器来处理   在未调用Dispose时释放资源。

另请参阅MSDN Object.FinalizeMSDN Implementing Finalize and Dispose to Clean Up Unmanaged Resources

如果你的继承链中没有合适的终结器,也许这就是你警告的原因?

另请注意(作为反例),Microsoft建议使用者不应直接调用Dispose()MSDN using statement documentation州:

  

通常,当您使用IDisposable对象时,您应该声明和   在using语句中实例化它。

使用者的首选方法是“使用”IDisposable资源,如下所示:

   using (FTP myDisposableFTP = new FTP()) {
     ...
   }

这基本上是“语法糖”,以确保在您使用可支配资源(即Dispose()块的结尾)时调用using方法,或者重要的是,如果在 using块中发生异常。

此模式还避免了对实例引用进行null检查的要求,因为实例已在块的开头构造。它还确保无法重新分配对象(保护底层资源不会被意外打开,即使您的原始引用超出范围)。

但我认为你可以将这种模式(或等效的try / catch / finally)合并到你的继承/接口实现中是值得怀疑的。

所以是的,调用Dispose()方法在功能上是好的,只要你记得在需要它的所有情况下调用它(例如在你的异常处理中),或者你重新暴露它的地方向您的消费者提供正确处理作为“包装”IDisposable实现的一部分。但是如果您的资源不受管理,您还应该添加终结器。