理解一次性物体

时间:2013-09-29 09:13:36

标签: c# .net garbage-collection dispose idisposable

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

我们假设我有这段代码:

public class SuperObject : IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) { }
}
  • 我需要protected virtual void Dispose(bool)上的SuperObject吗?因为那里没有什么可以处理的。
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
        }
    }
}

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

public class Moo : Controller
{
    Custom c;

    public Moo()
    {
        c = new Custom();
    }

    // Use c throughout this class        
}

如何在c中妥善处理Moo

2 个答案:

答案 0 :(得分:6)

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

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

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

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

有关详细信息,请参阅此问题:Minimal IDispose implimenation for managed resources only

所以在你的情况下,以下是最小的暗示:

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();       
        }
    }

答案 1 :(得分:2)

  

如何在c中正确处理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逻辑。最好只进行一次处理,并且您可能希望在处置后捕获使用。
  • 省略析构函数(终结器)本身就是一个好主意,但是你现在有了额外的约束,即派生类不应该拥有非托管资源。