【发布时间】:2018-09-26 11:52:45
【问题描述】:
在 UMLs 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# 中子对象的过早处理方面是否有某种最佳实践?我的第一个想法是在处置子对象时使用回调函数/委托将自己从活动实例列表中删除,但对我来说这听起来相当笨拙。
- 还有其他借口可以让我免去责任吗?
- 如果是
从架构的角度来看,主要问题是,每个能够获得Child
实例的人都可以看到IDisposable
。隐藏它基本上意味着利用 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;
}
}
【问题讨论】:
-
我可能会使用
IsDisposed
事件(自行实现),在子项被处置时将其从父项中移除。 -
这似乎是使用
IDisposable
的常用方式,但每个人都不清楚(不看类 Disposable 模式)会发生什么 -
一种选择是在
Child
中使IDisposable
的接口实现显式:void IDisposable.Dispose()
- 然后调用者必须将孩子强制转换为IDisposable
才能处理它,即((IDisposable)child).Dispose();
-
@stuartd 这对
using
语句没有帮助,因为仍然允许使用这些语句。我也想到了它,但我似乎很容易出错。 -
这是一个有趣的问题,虽然是关于具体实现,但与此问题密切相关:*.com/questions/50912160/…
标签: c# .net architecture uml