【问题标题】:Can I safely clean up after a readonly object field?我可以在只读对象字段之后安全地清理吗?
【发布时间】:2011-04-28 22:57:06
【问题描述】:

假设我有一个带有对象字段的类。当调用 Dispose() 时,我想清除对该对象的引用。私有字段只能设置一次,所以理想情况下我希望它是只读的,但如果它是只读的,当我尝试在 Dispose() 期间释放对对象的引用时会出现编译时错误。理想情况下,我希望安全处置并将 _value 字段标记为只读。这可能甚至是必要的吗?

public class Foo : IDisposable
{
      public Foo(object value)
      {
            _value = value;
      }

      public object Value { get { return _value; } }
      private readonly object _value;

      public void Dispose()
      {
            //Cleanup here
            _value = null     // causes compile time error
      }
}

【问题讨论】:

  • 在此示例中,您正在滥用 IDisposable。 IDisposable 旨在清理本机资源以进行确定性清理。

标签: c# readonly dispose


【解决方案1】:

这不是必需的,即使有可能。

Dispose 通常用于清理非托管资源,尽管该规则可能存在例外情况(注意 cmets)。但是,在这种情况下,您应该允许垃圾收集器完成其工作。一旦对象被认为没有活动的根,它将不确定地运行。在正常情况下,您不需要采取行动来强制它。只需使用适当有限范围内的对象编写代码,就可以了。

【讨论】:

  • 在许多情况下,即使对于没有非托管组件的对象,也可以适当且必不可少地处置。任何从长寿命对象接收事件的对象都必须取消订阅其所有事件(通常从 Dispose 完成),以避免被长寿命对象保持活动状态。
【解决方案2】:

将引用设置为 null 实际上并没有做任何事情。当不再有对它的任何引用时,垃圾收集器将清理该对象,在这种情况下,由于您在 Dispose 方法中执行此操作,因此大概 Foo 的实例将不再对它有任何引用,并且在时间可能没有意义。通常,您实现 Dispose 模式是因为您的类型作为成员有一个本身实现 IDisposable 的类(在这种情况下,类型是 Object,它不实现 IDisposable),或者您有想要确定性释放的非托管资源。您可以找到对 Dispose 模式 here 的描述。请注意,如果您创建实现 IDisposable 类型的只读成员变量,则可以在 Dispose 方法内对该对象调用 Dispose 方法:

public class SomeClass : IDisposable
{
    private Boolean mDisposed;
    private readonly MemoryStream mStream = new MemoryStream(); // Could be any class that implements IDisposable
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected void Dispose(Boolean disposing) {
        if (disposing & !mDisposed) {
            mStream.Dispose();  // Could and should call Dispose
            mDisposed = true;
        }
        return;
    }
}

之所以有效,是因为只读性质是对对象的引用,而不是对象本身。

【讨论】:

  • 嗨,GC.SuppressFinalize(this);有什么影响吗?据我了解,GC 不会保留 SomeClass 对 Finalization 队列的引用,因为没有定义 Finalizer。
  • 在我的回答中关注处置模式的链接;调用 GC.SuppressFinalize 是模式的一部分。在这种情况下,它可能没有任何影响,但这是一个好习惯,因为如果 GC 调用 Finalize 方法会影响性能。
【解决方案3】:

这既不必要也不正确。想要做您在问题中提出的问题似乎表明您正在某个地方访问已处置的对象,这是错误的。

与其尝试做你所要求的,你或许应该实现IsDisposed(顺便说一句,它是standard Dispose pattern的一部分)并首先检查它。

正如其他人所指出的,Dispose 模式旨在释放非托管资源。

【讨论】:

    【解决方案4】:

    这是一篇较旧的帖子,但我经常遇到同样的问题,因为我取消订阅了我订阅的对象。

    我在 dispose 期间取消订阅是因为这些对象的寿命比这个对象长,并且委托的实现方式意味着发布者让订阅者保持活动状态,而不是像我们想象的那样相反。

    但是,当您取消订阅事件时,您自然也希望清除对发布者的引用,这真的没什么大不了的。我建议您保留“只读”约束,因为它使规则更清晰,并且在对象仍然存在时代码更健壮。如果这意味着您在 dispose 后与引用坐在一起,那没关系,因为该对象现在 可收藏

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-13
      • 2023-03-29
      • 1970-01-01
      • 2019-12-03
      • 2021-05-18
      • 2010-12-02
      • 1970-01-01
      • 2016-01-03
      相关资源
      最近更新 更多