实施IDisposable是否与组合聚合相矛盾?

时间:2018-09-26 11:52:46

标签: c# .net architecture uml

在UML composition聚合中,我倾向于使用IDisposable接口/模式来强制Child在没有Parent”的情况下不存在-要求组成要求:

public class Parent : IDisposable
{
    private readonly _childs;
    public IReadOnlyCollection<Child> Childs => _childs;

    public Parent()
    {
        _childs = new List<Child>();
    }

    public Child CreateChild()
    {
        var child = new Child();
        _childs.Add(child);
        return child;
    }

    public void Dispose()
    {
        foreach (var child in _childs)
            child.Dispose();
    }
}

public class Child : IDisposable
{
    internal Child() {}

    public void Dispose()
    {
         //Cleanup object, imagine an idempotent implementation
    }
}

到目前为止,太好了。但是现在想象一下这段代码:

var parent = new Parent();
var child = parent.CreateChild();
child.Dispose();
//At this point parent.Childs contains a disposed child object

由于我目前正在开发的图书馆中遇到这种情况,所以我想到了几个问题:

  • 可以parent.Childs包含(实际上)不可用的对象吗?
    • 如果是
      • 您会忽略它吗,因为这是用户自己决定是否过早处置它?
    • 如果没有
      • 在C#中,如何处理子对象的过早处置是否存在某种最佳实践?我的第一个想法是在处置子对象时使用回调函数/委托将其从活动实例列表中删除,但对我来说听起来很笨拙。
      • 还有另一个借口可以让我洗责任吗?

从体系结构的角度来看,主要问题是,IDisposable对于每个能够获取Child实例的人都是可见的。隐藏它基本上意味着利用OO多态并将提取处理的能力提取到一个不可见的实现中。但是对于域模型中的许多类来说,这绝对是一个ating肿的因素,而没有其他好处。此外,它固有地将UML组合聚合解释为” {Child只能 Parent破坏,我认为这是错误的:

public interface IChild
{
    //Child methods
}

internal class Child : IChild, IDisposable
{
    //See implementation above
}

public class Parent : IDisposable
{
    public IReadOnlyCollection<IChild> Childs => _childs;

    public IChild CreateChild()
    {
        var child = new Child();
        _childs.Add(child);
        return child;
    }
}

1 个答案:

答案 0 :(得分:2)

  

parent.Childs包含(实际上)不可用的对象可以吗?

是的,但是您永远不要再碰它。通常,处置时触摸ObjectDiposedException会丢掉它。

  

我的第一个想法是在处置子对象时使用回调函数/委托将其从活动实例列表中删除,但是对我来说这听起来很笨拙。

笨拙而危险。想象您有一个财务数据集合,突然有些对象因为某些开发人员错误地放置了一个对象而被删除。而是如上所述抛出异常。

剩下的问题是:子对象应该实现IDisposable,还是应该具有仅父类可以使用的'dispose'方法?这种方法对我来说似乎更有意义。