处理对象(简化)

本文关键字:简化 对象 处理 | 更新日期: 2023-09-27 18:15:41

我在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;
    }

完整的源代码位于这里。

处理对象(简化)

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

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

public sealed class ToBase64Transform : ICryptoTransform
{
    private bool disposed;
    public void Dispose()
    {
        if (disposed) return;
        // Dispose managed objects
        disposed = true;
    }

如果没有任何管理的一次性组件或者,那么…只是不要让它实现IDisposable

我不确定我是否会期望"Clear()"方法调用"Dispose()",但也许这是加密流上下文中的规范。

几点:

  • Mono暴露的公共API 必须与Microsoft提供的API匹配,否则会出错。这包括终结器(即使Mono不需要它们)。Mono在托管代码中实现比Microsoft更多的东西是很常见的(实际上在密码学中很常见);

  • 类型不是sealed,所以必须调用Dispose(bool)方法(例如从终结器),也不是abstract,所以必须实现IDisposable接口;

  • Mono带有一组广泛的单元测试。当某些东西看起来奇怪时,看看它们是一个好主意。匹配MS实现并不总是直截了当的,MSDN文档(虽然很好并且经常更新)很少足够或完全完整/正确。

  • 在这种情况下,Dispose(bool)中的代码是不需要的。我怀疑它来自模板(或从另一个文件复制/粘贴),或者作者不确定这些代码将来是否会转移到非托管代码中。删除它不太可能改变性能/大小,但可以自由提交bug报告(或pull request)来删除它。

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

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

  1. 必须有一些方法,通过这些方法派生类可以请求从基类的IDisposable.Dispose()实现调用派生类的Dispose逻辑,而不必重新实现IDisposable.Dispose()本身。
  2. 如果派生类重新实现了IDisposable。必须有某种方法,基类可以通过这种方法向派生类公开它自己的已处置逻辑,因此派生类是可处置的。Dispose例程可以调用它。

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

这个想法是所有实现IDisposable的可继承类都有一个受保护的虚方法,其签名不匹配可能公开的"void Dispose()";IDisposable.Dispose()将为其所有的处置逻辑调用此方法(参数值为True),而覆盖此方法的派生类可以通过调用其父类的相应方法来调用基本处置逻辑。尽管Microsoft允许"Finalize"方法调用这个值为false的方法,但实际上并不需要这样做。将Finalize方法(或c#析构函数)添加到不包含所需的所有条款的类中(包括"GC.KeepAlive()在关键位置的调用")可能是导致微妙bug的破坏性更改。如果一个类需要使用非托管资源,而父类不需要,那么应该通过定义新的可终结类来处理,将非托管资源封装到托管对象中,然后让继承的类保存这些托管对象。