处置对象(简化)

时间:2011-11-24 11:49:58

标签: c# .net mono dispose idisposable

我在Mono重新实现加密转换时发现了这段代码。

我没有修改或简化任何事情 - 这就是它实际上如何(有// Dispose unmanaged objects之类的评论,但实际上并没有做任何事情。)

现在 - 与IDisposable相关的代码对我来说似乎是多余的。 这可以在不破坏重要内容的情况下以某种方式完全简化/删除吗?

public class ToBase64Transform : ICryptoTransform
{
    private bool disposed;

    ~ToBase64Transform()
    {
        Dispose(false);
    }

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

    void IDisposable.Dispose()
    {
        Dispose(true);
        // Finalization is now unnecessary.
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed) return;

        if (disposing)
        {
        }

        disposed = true;
    }

完整来源位于here.

4 个答案:

答案 0 :(得分:4)

如果它包装了非托管组件,那么这是最合适的实现。

如果没有任何非托管组件,并且它不会被子类化,那么是;你可以删除终结器并让它只有一个简单的Dispose()

public sealed class ToBase64Transform : ICryptoTransform
{
    private bool disposed;

    public void Dispose()
    {
        if (disposed) return;
        // Dispose managed objects
        disposed = true;
    }

如果没有托管一次性组件 ,那么......只是不要让它实现IDisposable

我不确定我会期望“Clear()”方法调用“Dispose()”,但这可能是加密流上下文中的常态。

答案 1 :(得分:4)

几点:

  • Mono公开的公共API 必须匹配Microsoft提供的公共API,否则事情就会中断。这包括终结器(即使Mono不需要它们)。 Mono在托管代码中实现的内容比Microsoft更常见(实际上在密码学中很常见);

  • 类型不是sealed因此Dispose(bool)方法必须(例如来自终结器)和abstract所以{{1}接口必须实施;

  • Mono附带了大量unit tests。当某些东西看起来很奇怪时,最好看一下它们。匹配的MS实现并不总是直截了当的,MSDN文档(虽然很好并经常更新)并不是很少或完全/正确。

  • 在这种情况下,IDisposable内的代码不是必需的。我怀疑它来自一个模板(或来自另一个文件的复制/粘贴),或者作者不确定此代码将来是否会转移到非托管代码中。删除它不太可能改变性能/大小,但可以随意提交错误报告(或拉取请求)以删除它。

答案 2 :(得分:3)

这是实现IDisposable的完全标准方式。同意,没有工作,但如果它必须与MS.Net兼容,那么最好做得对。

答案 3 :(得分:1)

从实现IDisposable的基础继承的类通常需要确保对IDisposable.Dispose的调用将调用基类'处理逻辑以及它自己的逻辑。这要求必须至少应用两个条件中的一个:

  1. 必须有一些方法可以让派生类可以要求从基类调用派生类Dispose逻辑。 IDisposable.Dispose()的实现,而不必重新实现IDisposable.Dispose()本身。
  2. 如果派生类确实重新实现了IDisposable.Dispose,那么基类必须有一些方法可以将自己的处理逻辑暴露给派生类,因此派生类' IDisposable.Dispose例程可以调用它。

有多种方法可以满足至少一种这些条件;在不同的情况下,不同的方法可能是最佳的。最值得注意的是,对于具有与IDisposable.Dispose()在语义上相同的公共Dispose()方法的类,最简单的方法是让基类具有隐式实现IDisposable.Dispose的公共虚拟Dispose()方法。如果派生类重写该方法,它将覆盖IDisposable.Dispose的行为,但其Dispose()可以调用base.Dispose()来激活父级的dispose逻辑。然而,这种方法有一个缺点:某些类可能不希望公共Dispose()方法在语义上与IDisposable.Dispose()相同。尽管在适合的类中使用该方法可能是可行的,而对于其他类也可以采用其他方法,但Microsoft认为对所有类都采用通用方法会更好。

这个想法是所有实现IDisposable的可继承类都有一个受保护的虚拟方法,其签名与可能的公共" void Dispose()&#34 ;;不匹配。 IDisposable.Dispose()将为其所有处理逻辑调用此方法(参数值为True),并且覆盖此方法的派生类可以通过调用其父级的相应方法来调用基本处理逻辑。虽然微软承认了“终结”的可能性。调用此方法的方法的值为false,实际上并不需要这样做。 将Finalize方法(或C#析构函数)添加到一个不包含 all 所需条款的类中 - 包括" GC.KeepAlive()调用键如果某个类需要使用非托管资源但父类不需要,那么应该通过定义新的可终结类来将非托管资源封装到托管对象中来处理这些错误。然后让继承的类保存这些托管对象。