【问题标题】:Should we implement IDisposable if one member is IDisposable如果一个成员是 IDisposable,我们是否应该实现 IDisposable
【发布时间】:2011-09-19 06:50:07
【问题描述】:

我想是的。但是看看 ASP.NET 中的一个内置类:

public sealed class HttpPostedFile
{
    public Stream InputStream { get; }   // Stream implements IDisposable
    // other properties and methods
}

假设我有一个名为 fileHttpPostedFile 实例。由于没有显式调用Dispose的方法,所以file.InputStream.Dispose()在被破坏之前不会被调用,我认为这违背了IDisposable的初衷。我认为正确的实现应该包含标准的IDisposable 实现。因此,如果其中一个成员实现了IDisposable,则该类也需要实现它。

你有什么看法?好像有点复杂。

【问题讨论】:

    标签: c# .net asp.net asp.net-mvc idisposable


    【解决方案1】:

    一般来说,如果您拥有该属性所代表的资源,您应该实现IDisposable - 请参阅this question for a discussion on this subject

    我会说,因为 HttpPostedFile 在处理 HTTP 请求期间被实例化,它不拥有流,因此不会释放它。当 HTTP 请求处理完成时,该流将被释放。

    【讨论】:

    • 哦,看来我的问题是重复的。感谢您的链接。我会在 1 分钟内接受这个答案。
    • +1,如果您是构建对象的人,通常只有您负责处理对象..
    【解决方案2】:

    如果您的类创建了一个或多个 IDisposable 对象并拥有对它们的唯一引用,那么您的类几乎肯定应该实现 IDisposable 并处置它创建的 IDisposable 对象。如果将一个或多个IDisposable 对象传递到您的类的构造函数中,那么您需要考虑以下几种情况:

    1. 您的创建者可能希望在您使用完 IDisposable 后继续使用它,并且肯定会知道何时不再需要它(您的类的语义会让他知道您已使用它)。
    2. 您的创建者在您使用完 IDisposable 后将不想使用它,并且可能不知道您何时才能使用它。
    3. 您的类可能会在对应于上述 (1) 的某些情况下和在某些情况下 (2) 使用,但您的创建者会提前知道适用哪种情况。
    4. 您的创建者无法预测他是否会在您完成对象后继续使用它。

    对于场景 #1,您无需实现 IDisposable,尽管实现无操作 IDisposable 处理程序并让您的消费者使用它可能不是一个坏主意,以防其他场景适用于未来。

    对于场景#2,您的对象应该拥有IDisposable 的所有权,并且在完成后应该拥有Dispose。我真的不喜欢让对象获得IDisposables 的无条件所有权;我更喜欢按照 #3 来实现。

    有两种处理 #3 的方法。我更喜欢的一个是让您的对象与IDisposable 一起获取一个参数(Booleanenum),表明它是否应该获得IDisposable 的所有权。你的班级无条件地实现IDisposable;实现处理它拥有的任何对象,但不是那些它没有拥有的对象。另一种方法是拥有两个具有公共基类的子类——一个子类实现IDisposable,另一个不实现。我更喜欢前一种模式,因为它允许添加一种方法来用新方法替换IDisposable(它可能会或可能不会拥有所有权)。例如,如果我正在实现一个带有Image 属性的控件,我将有一个SetImage 方法,它带有一个参数来指定控件是否应该拥有传入的图像;如果它拥有旧图像,该方法将Dispose 拥有它,然后可以获取或不拥有新图像的所有权。

    bool OwnMyImage;
    Image MyImage;
    void SetImage(Image NewImage, bool TakeOwnership)
    {
        IDisposable oldDisposable; // Could reuse one variable for multiple IDisposables
        if (OwnMyImage)
        {
            oldDisposable = Threading.Interlocked.Exchange(MyImage, null);
            if (oldDisposable != null)
            {
                oldDisposable.Dispose();
            }
        }
        OwmMyImage = TakeOwnership;
        MyImage = NewImage;
    }
    

    场景#4 很复杂;处理它的最佳方法可能是让您的对象通过引发Disposed 事件来实现IDisposable。如果您是最后一个使用该对象的人,您的创建者可以使用该事件来执行 Dispose 对象,或者调整标志或计数器,以便其他代码知道该对象不应代表您闲置。

    【讨论】:

      【解决方案3】:

      视情况而定。

      Stream 也由TextStream 实现(可能在StringBuilder 之上),因此不需要非托管资源。

      HttpPostedFile 可能根本不使用任何非托管资源,因此在垃圾收集器认为合适之前推迟解构是安全的。

      【讨论】:

        猜你喜欢
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 2023-03-20
        • 2010-09-11
        • 2014-04-06
        • 2011-03-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多