Контейнеры IOC и IDisposable - PullRequest
       46

Контейнеры IOC и IDisposable

9 голосов
/ 14 апреля 2010

Мне было рекомендовано, чтобы при использовании контейнера IOC я изменил это:

class Foobar: IFoobar, IDisposable {};

В это:

interface IFoobar: IDisposable{};
class Foobar : IFoobar{};

Мне интересно, нормально ли это, или это решает одну проблему и создает другую. Это, конечно, решает проблему, где я очень хочу это сделать:

using( IFoobar = myContainer.Resolve<IFoobar>() )
{ ... }

И теперь я знаю, что любая замена не вызовет ошибку во время выполнения.

С другой стороны, теперь все мои фиктивные объекты также должны обрабатывать IDisposable. Я прав, что большинство насмешливых фреймворков справляются с этим легко? Если да, то, возможно, это не проблема.

Или это? Есть ли еще одна скрытая ошибка, за которой я должен следить? Мне, конечно, приходит в голову, что если бы я использовал контейнер IOC не для модульных тестов / макетов, а для истинной независимости сервисов, то это могло бы быть проблемой, потому что, возможно, только один из моих заменяемых сервисов фактически имеет дело с неуправляемыми ресурсами (и теперь я ' я должен реализовать пустые операции «IDispose» в этих других службах).

Даже с этим последним вопросом, я полагаю, я мог бы жить, чтобы получить возможность использовать выражение «использование», как я продемонстрировал выше. Но придерживаюсь ли я популярного соглашения или мне не хватает совершенно другого и лучшего решения?

1 Ответ

11 голосов
/ 14 апреля 2010

Получение интерфейса от IDisposable - это, на мой взгляд, запах дизайна, который указывает на Leaky Abstraction . Как выразился Николас Блумхардт :

интерфейс [...] обычно не должен быть одноразовым. Тот, кто определяет интерфейс, не может предвидеть все возможные его реализации - вы всегда можете придумать одноразовую реализацию практически любого интерфейса.

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

Контейнер DI, достойный своей соли, должен знать, когда он создает экземпляр одноразового типа. Когда вы впоследствии попросите контейнер освободить граф объектов, он должен автоматически утилизировать одноразовые компоненты (если их время истекло в соответствии с их образом жизни).

Я знаю, что по крайней мере Касл Виндзор и Автофак делают это.

Так что в вашем случае вы должны сохранить свой тип следующим образом:

class Foobar: IFoobar, IDisposable {};

Вы также можете найти интересную статью Николаса Блюмхардта Зоопарк по связям - в частности, обсуждение Owned<T>.

...