首页 > 解决方案 > 实现 IDisposable 是否与组合聚合相矛盾?

问题描述

在 UML组合聚合中,我倾向于使用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

由于我目前在我开发的图书馆中面临这样的情况,我想到了几个问题:

从架构的角度来看,主要问题是IDisposable每个人都可以看到Child. 隐藏它基本上意味着利用 OO 多态性并将处置能力提取到一个不可见的实现中。但是对于域模型中的许多类,这绝对是一个臃肿的因素,没有额外的好处。此外,它固有地将 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;
    }
}

标签: c#.netarchitectureuml

解决方案


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

是的,但你不应该再碰它。通常你会ObjectDiposedException在处理时触摸它时抛出一个。

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

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

剩下的问题是:子对象应该实现IDisposable,还是应该有一个只有父类知道和可用的“dispose”方法?这种方法对我来说似乎更有意义。


推荐阅读