为什么一个类会显式地而不是隐式地实现IDisposable接口?

17

我正在使用FtpWebResponse类,但没有看到Dispose方法。 原来该类显式实现了IDisposable接口,因此在调用Dispose之前,您必须将实例强制转换为IDisposable:

// response is an instance of FtpWebResposne
((IDisposable) response).Dispose();

为什么这个类的设计者选择显式实现IDisposable接口?正如Anthony Pegram所说,这样做可以掩盖普通开发人员在每次使用类时不查阅文档就应该释放对象的事实。
4个回答

15

我同意,但奇怪的是这里的行为可能不同。反射器显示Dispose()调用Close(),然后调用一个名为OnDispose()的内部虚拟方法。而Close()则没有这样的调用,所以这两个方法的行为可能会有所不同(尽管对FtpWebResponse没有影响,因为OnDispose()的实现为空)。 - JMarsch
1
两个方法同名有什么问题吗?《CLR via C#》(第546页)指出:“一些提供dispose模式的类也为方便起见提供了Close方法;但是dispose模式并不需要这个方法。例如,System.IO.FileStream类提供了dispose模式,而这个类也提供了一个Close方法。程序员更自然地关闭文件而不是处理文件。” - MCS
1
@JMarsch:这可能是一个遗留问题;.NET 1.1 BCL类有许多情况下,CloseDispose的行为确实有些不同。据我所知,现在所有这些都已经被清理干净了,除了DbConnection和派生类型。 - Stephen Cleary
1
我同意,这可能是一个设计遗留问题,尽管看起来这个类是在2.0版本中引入的。根据框架指南,它似乎遵循了指南,但它没有遵循“建议将关闭实现与Dispose相同”的部分。 - JMarsch
3
我同意你的不同意见。一旦在对象上调用了Dispose()方法,就存在一个强烈的约定,不需要或者不能进行进一步的清理(例如,可以再次调用Dispose而不会引发异常,但它不应该产生任何影响)。但是,在Close方法周围没有这样的约定。一个对象支持Close方法,但为了允许Reopen方法而避免清除所有内容完全是可能的。 - supercat

5
  • 有时候一个类会有一个Dispose方法,它是接口的一部分,但实际上不需要被调用,因为唯一需要处理的资源是内存:例如MemoryStream。
  • 正如其他人所提到的,如果该类有一个Close方法,它与Dispose做相同的事情,可以说Dispose仅需要存在以支持“using”模式,因此最好明确指定。

1
除了已经说过的,我可能建议明确实现IDisposable鼓励使用using块,因为它可以用于任何实现IDisposable的类型,并且对大多数人来说更自然,写起来更容易:
using (var response = GetResponse())
{
    // do something
}

比这个更好:

var response = GetResponse();

// do something

((IDisposable)response).Dispose();

我不确定一个开发者在明确实现IDisposable时是否会有这样的意图,但这是可能的。


3
只有当你知道对象是可丢弃的时,它才会鼓励使用!问题在于,如果人们没有查阅文档,他们根本不会知道这一点。此外,请考虑代码库可能具有糟糕或根本没有文档的情况。 - Anthony Pegram

1

对我来说,这看起来有点奇怪。值得一提的是:基类(WebResponse)实现了一个Close()方法。反射器显示,WebResponse的Dispose()方法只调用Close()和一个什么也不做的内部OnDispose虚拟方法。

我必须承认,这对我来说有点可疑,但我敢打赌,他们明确地实现了IDisposable,以便在Intellisense中调用Close()或Dispose()时不会混淆。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接