C# 当显式释放所有成员时,类是否需要实现IDisposable?
试图了解何时需要实施IDisposable: 我写了一个小例子C# 当显式释放所有成员时,类是否需要实现IDisposable?,c#,.net-2.0,idisposable,C#,.net 2.0,Idisposable,试图了解何时需要实施IDisposable: 我写了一个小例子 public class FileManager { private FileStream fileStream; public void OpenFile(string path) { this.fileStream = File.Open(path, FileMode.Open, FileAccess.Read); } public void CloseFile(st
public class FileManager
{
private FileStream fileStream;
public void OpenFile(string path)
{
this.fileStream = File.Open(path, FileMode.Open, FileAccess.Read);
}
public void CloseFile(string path)
{
if ( this.fileStream != null && this.fileStream.CanRead)
{
this.fileStream.Close();
}
this.fileStream.Dispose();
}
}
// client
var manager = new FileManager();
manager.Open("path");
manager.Close("path");
这个类是否需要实现IDisposable,因为它有一个托管资源(FileStream),该资源保存在一个非托管资源(文件)上?或者我不必实现IDisposable,因为我正在清理类
困惑。如果不是声明性的,那么在这里实现IDisposable
没有任何真正的好处。如果有人看到您的类实现了IDisposable
,他就会明白,在某些地方,资源在使用后必须清理。它只是一个内置的.net
声明类型的约定,就像这样
如果您不使用该模式,您可以自由地这样做,但您违反了
.net
类型声明的建议和主要遵循的社区指南。如果您(或其他开发人员)使用FileManager类而忘记关闭它,您可能会希望实现IDisposable。请注意的示例如何在终结器中调用Dispose(false)
。为什么要将路径传递给close方法?在您的情况下,如果在打开另一个文件之前关闭了不同的文件,则您的经理似乎可以打开这些文件,因此您不想处理该对象
IMHO,我更愿意这样实施:
public class FileManager : IDisposable
{
private string path;
private FileStream fileStream;
public FileManager(string path)
{
this.path = path;
}
public void OpenFile()
{
this.fileStream = File.Open(path, FileMode.Open, FileAccess.Read);
}
public void CloseFile()
{
if ( this.fileStream != null && this.fileStream.CanRead)
{
this.fileStream.Close();
this.fileStream.Dispose();
}
}
public void Dispose(){
this.CloseFile();
}
}
// client
var manager = new FileManager("path")){
manager.OpenFile();
//Do other stuff
manager.CloseFile()
或
在调用
Close
方法的情况下,不需要单独处理。但是,这种情况下的一般做法是实现IDisposable
,因为不能保证类的使用者会调用Close
如果资源是在同一方法中创建并释放的,则只能可靠地省略
IDisposable
,因为这是确保资源在使用后确实被释放的唯一方法。您应该实现IDisposable
想象一下:
var manager = new FileManager();
manager.Open("path"); // <- throws for some reason
manager.Close(); // <- then this never gets called
。。。但这正是发明using和IDisposable的目的,你可以轻松地写:
using (var manager = new Manager()) {
manager.OpenFile("path");
} // and CloseFile will automagically be called here.
对于实现
IDisposable
且可能以非平凡方式实现的任何类型的每个实例,必须随时能够确定该实例将如何处置
d。在大多数情况下,这意味着每个IDisposable
实例都有一个定义良好的所有者,负责调用Dispose
。在类创建的FileStream
实例中,您的类是所有者,因为没有其他东西能够处置它
具有引用自己的IDisposable
实例的字段的类应该几乎总是实现IDisposable
,并使用其Dispose
方法来Dispose
它们所拥有的IDisposable
对象。你们班有这样一个领域;因此,它应该实现IDisposable
只要可能,应设计需要清理的类,以便对其调用IDisposable.Dispose
,就足以执行可能需要的任何和所有此类清理。在某些情况下,不使用其他方法执行清理可能是不切实际的,但这些情况非常罕见。如果可以设计一个类,使Dispose
能够处理所有必要的清理工作,那么应该这样做。在调用管理器.Close
之前引发异常时会发生什么情况?如果有疑问,运行FxCop-它检测并解释何时何地需要实现Dispose。@TimSchmelter-读了几遍,它看起来就像一个没有任何解决方案的参数。我没有看到任何答案@白ジェームス: 因此,我发布的链接只是作为补充,而不是重复或回答。这是我在大约5分钟内写的一个小样本,以帮助回答我的问题。我不打算用这个。答案和往常一样是“视情况而定”。因此,对于您提供的代码,这是我的答案。如果您有其他代码,我可以帮助您进行设计,看看实现IDisposable
是否合适。这件事没有黑白之分。有时实现IDisposable
是有意义的,有时则不然。+1我无意用示例代码来处理假设情况,但这一点很好@白ジェームス 错误处理完全是关于假设情况。。您必须始终假设在打开资源时或之后的某个时刻可能会抛出异常,并且必须为用户提供一种优雅地处理异常的方法。您可以通过try/finally“让他”这样做,或者通过实现IDisposable允许他使用“using”。人们会感谢你的。:)我想我是想说这是示例代码,只是用来帮助说明我的问题。在示例代码中,正在调用.Close,没有异常:)。这就是我要寻找的答案类型@白ジェームス: 很高兴它有用。我对那些建议类不应该实现IDisposable
的人感到有些恼火,如果它们使用其他方法进行清理,或者如果它们的清理需要执行通常与IDisposable
无关的操作。IDisposable
的全部意义在于能够说(1)创建需要清理的对象的人不必研究如何清理它——只需调用IDisposable.Dispose
;(2) 一个在其生命周期中拥有IDisposable
对象的类通常不必担心@白ジェームス: ...它将如何发现消费者何时使用完它,因为无论是谁创建了它,都应该调用IDisposable.Dispose
,或者将责任移交给其他某个对象,该对象的合同规定将调用IDisposable.Dispose
。当然,有可能在一个实体
try {
var manager = new FileManager();
manager.Open("path");
}
finally {
manager.Close();
}
using (var manager = new Manager()) {
manager.OpenFile("path");
} // and CloseFile will automagically be called here.