理解一次性物体

我已经看过像这样的问题,甚至我发现了很多,其中任何一个都为我提出了这个问题。

我们假设我有这个代码:

public class SuperObject : IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { } } 
  • 我是否需要在SuperObject上使用protected virtual void Dispose(bool) ? 因为那里真的没有什么可以处理的。
 public interface ICustom : IDisposable { } 
 public class Custom : ICustom { public SuperObject Super { get; protected set; } public Custom() { Super = new SuperObject(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public virtual void Dispose(bool disposing) { if (!disposing) return; if (Super != null) Super.Dispose(); } } 
 public class Foo { public Foo() { using (var c = new Custom()) { //do magic with c } } } 

现在如果我想要/需要/尝试在像System.Web.Mvc.Controller这样已经实现并实现了IDisposable的类上使用Custom会发生什么?

 public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } // Use c throughout this class } 

如何在Moo妥善处理?

通常的方法是应用标准的IDispoable实现 – 但是,如果您的类或从中派生的类将使用非托管资源, 实际上是必要的 – 这种情况实际上非常罕见 (当这种情况适用时,最好包装它自己的类中的非托管资源,具有完整的标准IDisposable实现)。

因此,假设您没有处理非托管资源(原始文件句柄,全局分配的内存等),并且只处理一次性的成员(即具有托管资源并实现IDisposable),那么您可以安全地获得一种方式,以最小化的方式实现IDispose – 即:

只需要一个void Dispose()方法。 在该方法中,只需调用disposable on dispoable members,然后在基类上Dispose,如果它是一次性的。 如果你有一个类层次,那么可以使这个Dispose虚拟化。 不需要Dispose(bool)方法。 也没有必要检查对象是否被处置 – 因为你所做的就是在其他对象上调用dipsose,而那些实现将进行检查。

如果您不喜欢mimimal appraoch,那么应用标准的完整实施(但并非绝对必要)。 即要么做一个标准的实施,因为你是一个遵循推荐方法的坚持者或做一个简单的最小(但正确)的实现 – 但不要在两者之间做一些事情(即不标准,不简单或不正确)!

有关更多详细信息,请参阅此问题: 仅限受管资源的最小IDispose implimenation

所以在你的情况下,以下是mimimal implimentation:

 public class SuperObject : IDisposable { public void Dispose() { // Dispose code...just call dispose on dispoable members. // If there are none then no need to implement IDisposable! } } public interface ICustom : IDisposable { } public class Custom : ICustom { public SuperObject Super { get; protected set; } public Custom() { Super = new SuperObject(); } public void Dispose() { if (Super != null) Super.Dispose(); } } public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } public Dispose() { if (c!=null) c.Dispose() base.Dispose(); } } 

请注意,如果Super对象没有任何可支配资源,那么实现IDisposable并使用Dispose方法就没有意义。 如果海关只有一次性对象是SuperObject,那么同样适用于那里,并且同样的逻辑通过Moo。 最后,如果以上所有情况都适用,并且周围没有其他一次性物品,那么您真正需要的是:

  public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } public Dispose() { base.Dispose(); } } 

如何在Moo妥善处理?

 public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } // Use c throughout this class protected override Dispose(bool disposing) { base.Dispose(disposing); if (disposing) c.Dispose() } } 

这也回答了你的第一个问题, Controller需要使其Dispose(bool)方法protected virtual否则上述方法是不可能的。

但是有几点说明:

  • 你没有任何isDisposed逻辑。 最好只进行一次处理,并且您可能希望在处置后捕获使用。
  • 省略析构函数(终结符)本身就是一个好主意,但是你现在有了额外的约束,即派生类不应该拥有非托管资源。