我应该在分配新对象之前处置旧对象吗?

时间:2014-08-08 08:08:51

标签: c# idisposable

假设我们有两个类 Foo Bar ,如下所示。

public class Foo
{
    public static Bar BarInstance { get; set; }

    public static void Main()
    {
        AssignBar("A");
        AssignBar("B");
    }

    private static void AssignBar(string name)
    {
        BarInstance = new Bar(name);
    }
}

public class Bar : IDisposable
{
    public Bar(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            return;
        }
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

当对象A被对象B替换时,我希望调用Dispose,因为没有对对象A的引用,但是它不会被调用。你能解释一下原因吗?

如果我希望处理对象A,我是否应该如下所述CurrentBar.Dispose

    private static void AssignBar(string name)
    {
        if (BarInstance != null)
        {
         BarInstance.Dispose();   
        }
        BarInstance = new Bar(name);
    }

3 个答案:

答案 0 :(得分:3)

Dispose不是特殊方法。它不会自动调用。你必须这样做。

private static void AssignBar(string name)
{
    if(BarInstance!=null)
    {
        BarInstance.Dispose();
    }
    BarInstance = new Bar(name);
}

我认为你对终结者和IDisposable感到困惑。在垃圾收集时调用终结器(虽然不可靠)。如果您已实施DisposablePattern,那么您将拥有一个从终结器调用的Dispose(bool)方法。垃圾收集过程中GC自动调用终结器。

请在此处阅读more info

答案 1 :(得分:3)

这取决于所有权。

BarFoo赋予Foo现在拥有 Bar的含义吗?

如果是,那么,在分配新实例之前,您应该在旧版本上调用Dispose

BarFoo,意味着它更多的是贷款,即。你可以引用和使用这个对象,但它是由其他东西拥有的吗?

如果是,那么,在分配新实例之前,不应在旧版本上调用Dispose


你的代码在这一点上并不完全清楚,我建议你清理它,以便将来更容易推理这种类型。

我认为你有三种可能情景中的一种:

  1. Foo始终拥有Bar。在这种情况下,我会将旧实例的处置放在属性的setter中,完全删除公共setter,如果获取新Bar实例的唯一方法是通过你声明的方法。
  2. Foo从未拥有Bar。在这种情况下,我不会添加任何处理旧实例的代码,但后来我质疑该方法的存在。在这种情况下,很可能没人会真正拥有新构造的实例。
  3. Foo仅拥有通过您的方法创建的Bar个实例,但不包含通过公共设置器提供给它的实例。在这种情况下,我会添加一个新字段来跟踪Foo是否拥有Bar,并在方法中将其设置为true,并在属性设置器中清除它。

  4. Dispose在任何方面都不是特别的,从C#的角度来看,它只是另一种方法,因此没有任何自动调用此方法。

    但是,如果对象引用非托管资源,当某个对象在某个时刻符合收集资格时,将执行其终结器释放那些非托管资源。但是,要在知道不再需要它们时确定性地释放它们,您需要致电Dispose

答案 2 :(得分:2)

运行时不会自动为您调用Dispose,您有责任确保调用它。您的对象将被垃圾收集,但这只能确保回收内存。它可以用来释放资源。

您可以使用using声明:

执行此操作
using(var x = new BarInstance())
{
  // Whatever
}

或者你可以自己打电话。在您的示例中,由于您要替换实例,因此需要调用Dispose,否则可能会导致资源泄漏。

您可以选择在班级~Bar中使用终结器。在终结器中,您可以处置您持有的任何资源。但是,当终结器将以非确定性方式调用时,如果垃圾收集器没有启动它甚至可能永远不会被调用。