代码之家  ›  专栏  ›  技术社区  ›  urig

IDisposable模式的一个有问题的例子?

  •  6
  • urig  · 技术社区  · 14 年前

    假设有3个类实现了IDisposable-A、B和C。类A和类B都依赖于类C。

    1. 如果说类A和类B的Dispose()的典型实现是:

      public void Dispose()
      {
          if (m_C != null) m_C.Dispose();
      }
      
    2. 如果有一个实例A和实例B共享同一个实例C,那么如何克服处理实例A会损坏实例B的问题?

    3. 最后一分钟补遗-如果在第2点中是一个实例化所有实例的DI容器,谁负责处理对象?是容器本身吗?怎么用?

    谢谢, 乌里格

    10 回复  |  直到 14 年前
        1
  •  12
  •   Jon Skeet    14 年前

    依赖 有一个公认的“拥有者”来决定何时应该处置资源。

    如果A和B需要引用C的同一个实例,那么它们中只有一个应该充当“所有者”。

    可以 做一些相当于引用计数的事情,我通常发现最好只是记录谁“拥有”了什么。例如,创建 Bitmap 从那一刻起 位图 拥有这条小溪,你不应该自己处理。这可能会导致一些问题,但它最终比尝试挖掘引用计数更简单。

        2
  •  4
  •   Mongus Pong    14 年前

    做一个空检查不会有帮助,就像B处理C一样,这不会更新a的引用。

    一般来说,创建C的类应该是处理它的类。

        3
  •  1
  •   Alex F    14 年前

    只有一个实例必须是所有者,它负责处理。非所有者实例应该使用像Attach这样的函数获取C引用,并且不应该处理它。

        4
  •  1
  •   Wim Coenen    14 年前

    最后一分钟补遗-如果在第2点 它是一个实例化的DI容器 处理物品?是那个吗

    是的,集装箱里有 IDisposable 它创建的对象。容器在自行处理时处理这些对象。默认情况下,所有DI容器都应该已经这样做了。

    有时,DI框架为您提供了一种获得所有权的方法。例如,在Autofac中,您可以请求 Owned<T> Owned<T>.Dispose() 当你处理完这个物体的时候。如果要通过注入的 Func<Owned<T>>

        5
  •  1
  •   Rob Levine    14 年前

    创建

    很可能有一个“outer”类创建了C,然后直接或间接地将其传递给A和B。这可能是负责C的生命周期的自然候选者,应该处理它。

    [编辑:回应OP的评论] 听起来你应该再看看这里的设计。这是否意味着需要重构?

    你有一个C类需要处理,这是由a和B使用;您是否应该让一个类全权负责通过a和B编组C,而不是让它们自己从DI容器创建C?或者说C更像是一个单子。它真的需要处理吗?

    我想我想说的是,这感觉可能指向一个设计,需要一点改变;用挑剔的眼光再看一眼。

        6
  •  0
  •   Joel Etherton    14 年前

    我认为有两种方法:

    1. 在C中创建父集合,并在a和B的dispose方法中,从子集合的父集合中移除self。如果父集合计数为0,则调用dispose。
    2. 延迟加载a和B中的属性以访问C。对C执行空检查,如果其他对象破坏了它,则重新实例化它(如果可能的话)。
        7
  •  0
  •   Adam Houldsworth    14 年前
    1. 很好的问题。立即想到的是,需要有逻辑来知道该对象当前有多少计数,这样它自己的处理例程就可以保护自己。信号量可以这样做,但是很重。

    我还想问,在现实世界的例子中,你在哪里会看到这种情况,可能是设计上的差异。 更新:

        8
  •  0
  •   Tomas Aschan    14 年前

    C 两者都有 A B ,并检查该列表是否为空(当前正在处理的对象除外) Dispose 方法。

        9
  •  0
  •   Krzysztof Kozmic    14 年前

    除了乔恩所说的-创造者是主人,应该处理一次性的。

    不是每个组件都支持这一点(或者至少不是每个组件都完全支持)。 Castle Windsor does . Autofac也支持它。

        10
  •  0
  •   supercat    10 年前

    IDisposable 对象应该有一个所有者。如果一个资源需要在多个用户之间共享,其中任何一个都可能是最后一个使用它的用户,那么每个用户都应该持有对自己包装器的引用。包装器对象应该使用除 可识别的 与单个私有创建的内部包装器对象进行协调,然后该对象将调用 Dispose 在资源上。内部包装器对象不需要使用 因为它不公开,而且它不需要使用 可识别的 意味着它可以使用一种可以容纳多个所有者的清理方法。