2

我正在开发一个 OSS 项目,以使流行的MediaInfo 库更易于在 .NET 中使用,但这个问题是可以推广的。

如果派生类D在调用其基类DB的构造函数时总是实例化对象O。DB 将其值设置为发送给其构造函数的值,但该值本身在DB的基类B中声明:

  1. 谁“拥有” O(下面代码中的又名 mediaInfo)?
  2. 对于 .NET 应用程序,哪些应该实现 IDisposable?注意:O是非托管的,或者至少是围绕非托管库包装的托管对象的实例化,但确实需要以“ MediaInfo.Close(); ”的形式进行清理。我不确定这算不算“不受管理”。

为了帮助澄清,让我使用实际代码:

D派生自DB

// MediaFile is "D" 
public sealed class MediaFile : GeneralStream
{
    public MediaFile(string filePath)
        : base(new MediaInfo(), 0) {
        // mediaInfo is "O"
        mediaInfo.Open(filePath);
    }
}

DB设置其继承的O,派生自B

// GeneralStream is "DB"
public abstract class GeneralStream : StreamBaseClass
{
    public GeneralStream(MediaInfo mediaInfo, int id) {
        this.mediaInfo = mediaInfo; // declared in StreamBaseClass
        // ...
    }
}

B声明O

// StreamBaseClass is "B"
public abstract class StreamBaseClass
{
    protected MediaInfo mediaInfo; // "O" is declared
    // ...
}
4

3 回答 3

2

持有对资源的引用的对象拥有它。

StreamBaseClass有参考mediaInfo,应该实施IDisposable。引用和Dispose方法将自动由派生类继承。

于 2012-03-11T18:30:37.983 回答
1

如果类 C 拥有一个变量,该变量是实现 IDisposable 的非公开局部变量 V,则 C 应该是 IDisposable 并且 C 的 IDisposable 应该处置 V。

如果类 D 拥有本机资源 N,则 D 应该是 IDisposable(删除 N),并且还应该有一个可终结的析构函数,该析构函数在自身上调用 Dispose() 以释放 N。

如果你遵循这个模式,那么如果你曾经有一个 IDisposable,你应该总是在完成后 Dispose() 它,这将删除对象树下的所有内容;但如果有人忘记了你(阅读:同事、你的图书馆的用户等)也不会泄漏任何对象,因为本机资源将被 D 的终结器清理。

于 2012-03-11T18:30:05.940 回答
1

在没有任何明确协议的情况下,an 的责任IDisposable属于创建它的对象。在资源的创建者可能不知道消费者的生命周期的情况下,通常使用相反的协议。我建议在许多情况下,当构造函数或工厂方法正在生成可能是传入的最后一个使用者时IDisposable,该方法应该接受一个参数,指示它是否应该接受调用的责任Dispose,或者接受一个回调委托,该委托将,如果非空,则在消费者不再需要该对象时调用。如果对象的创建者比消费者活得更长,它可以传递 null;如果创建者在对象被移交后将不再使用它,它可以传递对象的Dispose方法。如果创建者不知道它是否会比消费者更长寿,它可以传递一个方法来确定是否仍然需要该对象,Dispose如果不需要则调用。

关于您的特定情况,IDisposable在链式构造函数调用中构造一个是资源泄漏的秘诀(因为无法将链式构造函数调用包装在 try-finally 块中)。如果您要以某种方式安全地处理它(例如,使用工厂方法而不是链式构造函数,或者使用[threadstatic]hack),我建议因为对象的创建者(派生类)将知道对象的生命周期消费者(基类)、所有权和清理责任应该由对象创建者承担。

于 2012-03-12T18:47:01.430 回答