在哪里调用在构造函数中创建的IDisposable的Dispose()?

时间:2014-09-29 10:33:53

标签: c# .net dispose idisposable

在哪里为对象拥有的Dispose()个对象调用IDisposable

public class MyClass
{
    public MyClass()
    {
        log = new EventLog { Source = "MyLogSource", Log = "MyLog" };
        FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
    }


    private readonly EventLog log;
    private readonly FileStream stream;

    // Other members, using the fields above
}

我应该为此示例实现Finalize()吗?如果我什么都不执行怎么办?会有问题吗?

我的第一个想法是MyClass应该实现IDisposable。但an MSDN article中的以下陈述使我感到困惑:

  

仅在直接使用非托管资源时才实施IDisposable。如果您的应用只使用实现的对象   IDisposable,不提供IDisposable实现。

这个陈述是错的吗?

3 个答案:

答案 0 :(得分:25)

如果MyClass 拥有 IDisposable资源,则MyClass本身应为IDisposable,并且应该在{Dispose()时处置封装的资源在MyClass上调用1}}:

public class MyClass : IDisposable {
    // ...
    public virtual void Dispose() {
        if(stream != null) {
            stream.Dispose();
            stream = null;
        }
        if(log != null) {
            log.Dispose();
            log = null;
        }
    }
}

不,你不应该在这里实现终结器。

注意:替代实现可能类似于:

private static void Dispose<T>(ref T obj) where T : class, IDisposable {
    if(obj != null) {
        try { obj.Dispose(); } catch {}
        obj = null;
    }
}

public virtual void Dispose() {
    Dispose(ref stream);
    Dispose(ref log);
}

答案 1 :(得分:1)

对于包含其他IDisposable个对象it's a good and recommended practice to implement IDisposable on your own object的对象,因此使用您的类型的其他对象可以将其包装在using语句中:

public class MyClass : IDisposable
{
    public MyClass()
    {
        log = new EventLog { Source = "MyLogSource", Log="MyLog" };
        FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
    }


    private readonly EventLog log;
    private readonly FileStream stream;

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Free managed objects here
            stream.Dispose();
        }
    }

    // Other members, using the fields above
}

在您的情况下,您不会释放任何托管资源,因此不需要终结器。如果您 ,那么您将实现终结器并调用Dispose(false),向您的dispose方法指示它正在从终结器线程运行。

如果您未实施IDisposable,则需要将其留给GC清理资源(例如,关闭Handle上的FileStream一旦它开始收集,你就已经开业了。假设您的MyClass对象有资格进行收集,并且当前处于第1代。您将保持FileStream句柄处于打开状态,直到GC运行后清理该资源。此外,Dispose调用GC.SuppressFinalize的许多实现都是为了避免让对象处于另一个GC周期,从初始化队列传递到F-Reachable队列。

答案 2 :(得分:1)

围绕DisposeFinalize的许多建议都是由那些希望Finalize可用作主要资源清理机制的人编写的。经验表明这种期望过于乐观。面向公众的对象获取任何类型的资源并在方法调用之间保留它们应该实现IDisposable并且覆盖Finalize。如果一个对象拥有任何资源,否则如果它被放弃就不会被清除,它应该将每个这样的资源封装在一个私有对象中,然后使用Finalize清除该对象。资源(如果需要)。

请注意,类通常不应使用Finalize来清理其他对象持有的资源。如果Finalize在包含对另一个对象的引用的对象上运行,则通常会应用以下几个条件之一:

  • 其他对象没有其他引用,并且它已经运行Finalize,因此该对象不需要做任何事情来清理它。
  • 其他对象没有其他引用,它还没有运行Finalize但是计划这样做,所以这个对象不需要做任何事情来清理它。
  • 其他东西仍在使用另一个对象,因此该对象不应该尝试清理它。
  • 另一个对象的清理方法无法在终结器线程的上下文中安全地运行,因此该对象不应该尝试清理它。
  • 此对象仅有资格运行Finalize,因为所有必要的清理工作已经完成,因此该对象无需做任何事情来清理。

只有在可以理解为什么上述条件都不适用的情况下,才定义Finalize方法。虽然存在这样的情况,但它们很少见,最好不要使用Finalize方法而不是使用不合适的方法。