Здравствуйте, Tom, Вы писали:
Tom>·>Куча вредных антипаттернов, которые легко размазать по всему проекту, а обычно достаточно одного единственного constructor injection. И вычищать потом это — замучаешься.
Tom>Давай по конкретнее. Хоть один анти паттерн покажи мне и опиши в чём состоит проблема.
SL. В подавляющем числе случаев он не нужен. Проблема — он делает зависимости неявными.
методы-инициализаторы и property injection. Проблема — добавляет в объект опасное состояние "создан, но не очень-то ещё создан".
Магические строки. Ничем не лучше магических чисел.
Сканирование сборок. В подавляющем числе случаев он не нужен. Доставляет столько удовольствия исследовать что куда залетело и почему. Притом это можно исследовать только на запущенной системе в данном (часто prod) окружении.
Циклические зависимости. С DI+CI сделать цикл невозможно. Заставляет аккуратнее подходить к архитектуре приложения, а не всякие lazy/PI, которые тебе циклы создадут на ура.
Tom>·>выглядит ничуть не хуже.
Tom>Выглядит хуже. И создаёт конкретные проблемы в вполне конкретных случаях. Я больше скажу, с управлением временем жизни обьектов руками есть большие проблемы даже на теоретическом уровне.
Если это невозможно на теоретическом уровне, то как контейнер это будет разруливать?
Tom>Вот тебе прмиер. Есть обьект IFoo. Ну или IPlugin для наглядности. Есть пара его реализаций, одна из них использует unmanaget ресурсы и требует реализации IDisposable а другая нет. Кроме как калечного решения в виде наследованияч IPlugin от IDisposable для ручного управления зависимостями я не вижу.
Не понял. Давай более конкретный пример. Вот код:
var foo = fooProvider.giveMeFoo();
doSomethingWith(foo);
Если какие-то из IFoo могут быть disposable ты в данном месте обязан предполагать худшее и всегда освобождать foo, т.к. ты не знаешь какой из IFoo провайдер тебе выдаст. Поэтому будь добр оберни:
public void businessLogicMethod()
{
using(var foo = fooProvider.giveMeFoo())
{
doSomethingWith(foo);
}
}
А значит только наследование.
Если это известно в инфраструктурном коде, так и пиши в wiring модуле:
if(useDatabase)
{
using(var foo = new DatabaseFoo(connectionString))
{
doBusinessLogicWith(foo);
}
}
else
{
var foo = new InMemoryFoo();
doBusinessLogicWith(foo);
}
и спаси IFoo от leaking abstractions.
Tom>·>Единственное для чего эти контейнеры могут быть хороши это всякое Assembly Scanning, но реально проектов, где это необходимо — очень мало.
Tom>Контейнеры много чего могут но это бесполезно обьяснять человеку у которого в голове установка что они зло.
Но это всё не надо использовать. Контейнеры можно использовать для каких-то сложных случаев, только в довольно маленьком чётко отделённом контексте, в плагинном менеджере каком-нибудь например. Но пихать везде — антипаттерн.
Tom>·>Зато полная поддержка компилятора и IDE. А неудобно только с непривычки.
Tom>new это огромные трудности при написании тестов. Я про Integration тесты.
Tom>Руками собирать всё дерево зависимостей? Вопрос нахера, если я 2-мя движениями мышки могу в тесте подменить любую зависимость.
Нет, просто пишешь классы-модули, которые делают wiring тестируемых поддеревьев зависимостей. И тестируешь именно их. Иначе интеграционные тесты тестируют тестовый wiring.