我不喜欢样板代码:复制粘贴重用可能容易出错。即使您使用代码段或智能模板,也无法保证其他开发人员确实做到了,这也就意味着不能保证他们正确地做到了。而且,如果您必须查看代码,则必须理解它和/或对其进行维护。

我想从社区中了解到:我对类层次结构的IDispose实现是否是"traditional" dispose pattern的合法替代方案?合法是指正确,合理表现良好,强大且可维护。

我可以肯定这种选择是完全错误的,但是如果是这样,我想知道为什么。

此实现假定您完全控制类的层次结构。如果您不这样做,则可能必须重新使用样板代码。对Add *()的调用通常在构造函数中进行。

public abstract class DisposableObject : IDisposable
{
  protected DisposableObject()
  {}

  protected DisposableObject(Action managedDisposer)
  {
     AddDisposers(managedDisposer, null);
  }

  protected DisposableObject(Action managedDisposer, Action unmanagedDisposer)
  {
     AddDisposers(managedDisposer, unmanagedDisposer);
  }

  public bool IsDisposed
  {
     get { return disposeIndex == -1; }
  }

  public void CheckDisposed()
  {
     if (IsDisposed)
        throw new ObjectDisposedException("This instance is disposed.");
  }

  protected void AddDisposers(Action managedDisposer, Action unmanagedDisposer)
  {
     managedDisposers.Add(managedDisposer);
     unmanagedDisposers.Add(unmanagedDisposer);
     disposeIndex++;
  }

  protected void AddManagedDisposer(Action managedDisposer)
  {
     AddDisposers(managedDisposer, null);
  }

  protected void AddUnmanagedDisposer(Action unmanagedDisposer)
  {
     AddDisposers(null, unmanagedDisposer);
  }

  public void Dispose()
  {
     if (disposeIndex != -1)
     {
        Dispose(true);
        GC.SuppressFinalize(this);
     }
  }

  ~DisposableObject()
  {
     if (disposeIndex != -1)
        Dispose(false);
  }

  private void Dispose(bool disposing)
  {
     for (; disposeIndex != -1; --disposeIndex)
     {
        if (disposing)
           if (managedDisposers[disposeIndex] != null)
              managedDisposers[disposeIndex]();
        if (unmanagedDisposers[disposeIndex] != null)
           unmanagedDisposers[disposeIndex]();
     }
  }

  private readonly IList<Action> managedDisposers = new List<Action>();
  private readonly IList<Action> unmanagedDisposers = new List<Action>();
  private int disposeIndex = -1;
}


从某种意义上说,这是一个“完整”的实现,因为我提供了对终结的支持(知道大多数实现都不需要终结器),检查是否放置了对象等。实际的实现可能会删除终结器,例如,或者创建一个终结器。包含终结器的DisposableObject子类。基本上,我只考虑了这个问题就想到的一切。

我可能错过了一些极端情况和深奥的情况,因此,我邀请任何人在这种方法上戳破漏洞或通过更正予以支持。

其他替代方法可能是在DisposableObject中使用单个Queue 处理器,而不是两个列表。在这种情况下,当调用处置器时,会将它们从列表中删除。我可以想到其他一些细微的变化,但是它们具有相同的一般结果:没有样板代码。

最佳答案

您可能遇到的第一个问题是C#仅允许您从单个基类继承,在这种情况下,该基类始终为DisposableObject。在这里,您通过强制附加层使类层次结构混乱,以便需要从DisposableObject和其他对象继承的类可以这样做。

您还将在此实现的过程中引入很多开销和维护问题(更不用说每次有新人加入该项目时的重复培训费用,并且您必须解释他们应该如何使用此实现而不是已定义的模式) 。您知道有两个状态可以跟踪两个列表,在对操作的调用周围没有错误处理,在调用操作时的语法看起来“很奇怪”(虽然从数组调用方法可能很常见,简单地将()放在数组访问之后的语法看起来很奇怪)。

我了解减少您必须编写的样板数量的愿望,但是可处置性通常不是我建议采取捷径或以其他方式偏离图案的领域之一。我通常得到的最接近的结果是使用辅助方法(或扩展方法),该方法将实际调用包装在给定对象上。这些调用通常看起来像:

if (someObject != null)
{
   someObject.Dispose();
}


可以使用辅助方法来简化此操作,但请记住,FxCop(或其他任何检查正确的处置实现的静态分析工具)会抱怨。

就性能而言,请记住,使用这种类型的实现会进行很多委托调用。从本质上讲,这比常规方法调用的开销更高。

在这里,可维护性绝对是一个问题。正如我所提到的,每次有新人加入该项目时,您都要承担重复的培训费用,并且必须解释他们应该如何使用此实现而不是所定义的模式。不仅如此,每个人都记得将自己的一次性物品添加到列表中时遇到问题。

总的来说,我认为这样做是一个坏主意,这会导致很多问题,特别是随着项目和团队规模的扩大。

关于c# - 这是类层次结构的“传统”处置模式的合法替代方案吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1397196/

10-11 00:54