哪个类“拥有”非托管资源(并且实现了 IDisposable)?
-
11-12-2019 - |
题
我正在尝试 一个开源软件项目 使流行 媒体信息库 在 .NET 中更容易使用,但这个问题是可以概括的。
如果派生类 D 总是实例化一个对象 氧 当调用它的基类时 D B的构造函数。DB 将其值设置为发送到其构造函数的值,但该值本身在中声明 D B的基类 乙:
- 谁拥有” 氧 (在下面的代码中又称为 mediaInfo)?
- 对于 .NET 应用程序,其中哪一个应该实现 IDisposable?笔记: 氧 是非托管的,或者至少是包装在非托管库周围的托管对象的实例,但确实需要以“”的形式进行清理MediaInfo.Close();”。我不确定这算不算“不受管理”。
为了帮助澄清,让我使用实际代码:
D 源自于 D B:
// MediaFile is "D"
public sealed class MediaFile : GeneralStream
{
public MediaFile(string filePath)
: base(new MediaInfo(), 0) {
// mediaInfo is "O"
mediaInfo.Open(filePath);
}
}
D B 设置其继承的 氧, ,源自 乙:
// GeneralStream is "DB"
public abstract class GeneralStream : StreamBaseClass
{
public GeneralStream(MediaInfo mediaInfo, int id) {
this.mediaInfo = mediaInfo; // declared in StreamBaseClass
// ...
}
}
乙 宣称 氧:
// StreamBaseClass is "B"
public abstract class StreamBaseClass
{
protected MediaInfo mediaInfo; // "O" is declared
// ...
}
解决方案
持有资源引用的对象拥有该资源。
StreamBaseClass
有参考 mediaInfo
并应实施 IDisposable
. 。参考和 Dispose
方法将自动被派生类继承。
其他提示
如果c类拥有一个是一个infisposable的非公开局部变量v的变量,那么C应该是可IDisposable,C的IDisposable应该丢弃v。
如果d类别拥有本机资源n,则d应该是可可定义的(删除n)和也应该具有一个最终的析构函数,该析构函数呼叫呼叫本身释放n。
如果您遵循此模式,那么如果您有一个可IDispoSable,则应在您完成时始终将其丢弃()它,这将删除对象树下的一切方式;但如果有人忘记了你(阅读:你的图书馆的同事,你的图书馆的同事)不会泄露任何对象,因为D'S终结器将被清理。
的责任 IDisposable
属于该对象 创造 在没有其他明确协议的情况下。相反的协议通常用于资源的创建者可能不知道消费者的生命周期的情况。我建议在许多情况下,当构造函数或工厂方法生成的内容可能是传入的最后一个消费者时 IDisposable
, ,该方法应该接受一个参数,指示它是否应该接受调用的责任 Dispose
, ,或者接受一个回调委托,如果非空,则当消费者不再需要该对象时将调用该回调委托。如果对象的创建者比消费者活得更久,则可以传递 null;如果创建者在对象被移交后不再使用该对象,则可以传递该对象的 Dispose
方法。如果创建者不知道它是否会比消费者活得更久,它可以传递一个方法来确定该对象是否仍然需要并调用 Dispose
如果不。
关于您的具体情况,构建一个 IDisposable
链式构造函数调用中存在资源泄漏的根源(因为无法将链式构造函数调用包装在 try-finally 块中)。如果你要以某种方式安全地处理这个问题(例如使用工厂方法而不是链式构造函数,或者使用 [threadstatic]
hack),我建议,由于对象(派生类)的创建者将知道消费者(基类)的生命周期,因此所有权和清理责任应由对象创建者承担。