Противоречит ли реализация IDisposable агрегации композиций? - PullRequest
0 голосов
/ 26 сентября 2018

В 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;
    }
}

1 Ответ

0 голосов
/ 26 сентября 2018

Это нормально, что parent.Childs содержит (на практике) непригодный для использования объект?

Да, но вы никогда не должны касаться его снова.Обычно вы бросаете ObjectDiposedException при прикосновении к нему при удалении.

Моей первой мыслью было использование функции / делегата обратного вызова при удалении дочернего объекта для удаления себя из списка активных экземпляров., но для меня это звучит довольно неуклюже.

Действительно неуклюже и опасно.Представьте, что у вас есть коллекция финансовых данных, и внезапно некоторые объекты удаляются, потому что какой-то разработчик по ошибке удалил объект.Вместо этого выведите исключение, как указано выше.

Остается вопрос: должны ли дочерние объекты реализовать IDisposable или у них должен быть метод dispose, известный только и доступный для родительского класса?Мне кажется, что такой подход имеет больше смысла.

...