В UMLs состав агрегации Я склонен использовать 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-полиморфий и извлечение способности избавления к невидимой реализации.Но для многих классов в доменной модели это становится абсолютно раздутым фактором без дополнительных преимуществ.Кроме того, он по своей сути интерпретирует агрегацию композиции 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;
}
}