Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Все-таки не совсем. НС>Все таки совсем. Внутри любого контейнера — service locator
SL -- это подход, паттерн, когда программист самостоятельно вызывает Resolve для соотв. типа,
т.е. у нас что-то вроде
public Constructor(Container ioc)
{
var type1 = ioc.Resolve<IType1>();
....
}
В то время как DI
public Constructor(IType1 type1)
{
}
Т.е. SL реализуется с помощью контейнера, и как контейнер может реализовать SL с помощью... контейнера ?
S>>При DI мы получаем только нужны нам типы, про контейнер нам знать вообще не надо. НС>Тем не менее внутри любого известного мне контейнера ссылки на service locator присутвуют в публичном API.
Здравствуйте, ·, Вы писали:
S>>·>Только он нарисован вручную, в момент написания кода, а не автоматически сгенерирован в runtime. S>>Я именно про DAG, созданный в runtime. Т.е. помимо кода это где-то хранится(отражается) в памяти. ·>Всё равно я не понял вопрос "Без графа зависимостей этого не сделаешь?". ·>Если чё, объекты в памяти, которые ссылаются друг на друга и есть граф создаваемый и модифицируемый в runtime... DI тут непричём.
Все так, конечно, только вопрос кто и как формирует этот граф -- программист через new (не важно,
фабрика, билдер и проч. и проч.) или некий компонент, через рефлексию, например. https://blog.ploeh.dk/2011/07/28/CompositionRoot/
Здравствуйте, SkyDance, Вы писали:
AA>>Это все хорошо, но только для небольших проектов, если проект сложный, то и способ сборки частей будет чуть хитрее чем простая передача экземпляра в конструктор.
SD>В таком варианте — "способ сборки частей будет чуть хитрее" — тем более нельзя оставлять это на совести нетестируемого XML-файла в "конфигурации проекта".\
Да не спорю я что явное лучше не явного, но иногда динамическое связывание просто необходимо.
Вот например плагины пользователя как создать явно? когда имеется возможность загрузки/выгрузки?
Есть хорошая штука — проперти-бейс тестирование, интеграционные тесты. в учебно-полевых условиях тестируются функции.
такой эксперимент доказывающий, что софт работает корректно.
Здравствуйте, Poopy Joe, Вы писали:
PJ>Здравствуйте, Somescout, Вы писали:
S>>Банальная лень. Допустим мне в глубинах компонентов понадобился доступ к базе (оставим пока в сторонке вопросы архитектуры), как мне получить контекст базы без DI? PJ>Отличное описание. DI это костыль, когда лень думать об архитектуре, но не лень потом все это разгребать и отлаживать.
Какая это лень? Это способ уменьшить кол-во строк кода, один из базовых принципов KISS & DRY.
Представьте себе java 10-15 лет назад, не знаю как сейчас. Куча бесполезного кода чтобы создать объект.
И тут бах, DI, AOP и понеслась. Кол-во кода резко уменьшилось, а с ним возможность совершить опечатку, стало проще читать этот код.
Здравствуйте, Sharov, Вы писали:
S>>>При DI мы получаем только нужны нам типы, про контейнер нам знать вообще не надо. НС>>Тем не менее внутри любого известного мне контейнера ссылки на service locator присутвуют в публичном API.
S>Можно пример, ссылку?
Вот же(C# ):
using Microsoft.Extensions.DependencyInjection;
......
var scope = serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetService<IService>();
Здравствуйте, Sharov, Вы писали:
S>SL -- это подход, паттерн,
Да. И вокруг него построены все DI клнтейнеры.
S> когда программист самостоятельно вызывает Resolve для соотв. типа,
Нет.
The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator", which on request returns the information necessary to perform a certain task.
Википедия. Как видишь, ни слова про "самостоятельно вызывает Resolve". И прекрасно подходит для описания DI контейнеров.
S>Т.е. SL реализуется с помощью контейнера,
Контейнер и есть — service locator.
S>Можно пример, ссылку?
public static IServiceCollection AddSingleton<TService,TImplementation> (this IServiceCollection services, Func<IServiceProvider,TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
Здравствуйте, Sharov, Вы писали:
S>Все так, конечно, только вопрос кто и как формирует этот граф -- программист через new (не важно, S>фабрика, билдер и проч. и проч.) или некий компонент, через рефлексию, например.
Этот вопрос никак не вляет на суть того что такое DI контейнер, и является деталью его реализации.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Нет. НС>
НС>The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator", which on request returns the information necessary to perform a certain task.
НС>Википедия. Как видишь, ни слова про "самостоятельно вызывает Resolve". И прекрасно подходит для описания DI контейнеров.
Да. В википедии умеют в D. Inversion , поэтому они абстрагировались от "самостоятельно вызывает Resolve", потому что
это детали, а вместо написали:
which on request returns the information necessary to perform a certain task
НС>Контейнер и есть — service locator.
Да, я это в примере выше с двумя конструкторами отчетливо показал. Т.е. когда у нас D. Injection мы вообщем-то
вообще можем не знать про IoC контейнер (где-то там, а может и вообще нету). А когда у нас SL, то мы завязываемся
на контейнер. Короче, разница в том, как использовать контейнер -- явно SL, неявно -- DI.
S>>Можно пример, ссылку? НС>
НС>public static IServiceCollection AddSingleton<TService,TImplementation> (this IServiceCollection services, Func<IServiceProvider,TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
И о чем мне данная сигнатура должна сказать? Когда мне понадобиться тип TService он будет создан
Func<IServiceProvider,TImplementation> implementationFactory. Хорошо, и?
S>>Все так, конечно, только вопрос кто и как формирует этот граф -- программист через new (не важно, S>>фабрика, билдер и проч. и проч.) или некий компонент, через рефлексию, например. НС>Этот вопрос никак не вляет на суть того что такое DI контейнер, и является деталью его реализации.
Я не очень понимаю, что получится тогда без этой детали . Такая себе, краеугольная деталь.
Здравствуйте, Sharov, Вы писали:
S>Да. В википедии умеют в D. Inversion , поэтому они абстрагировались от "самостоятельно вызывает Resolve", потому что S>это детали
Нет, не потому что это детали, а потому что это не является признаком паттерна. Там правильное и точное определение, не надо к нему докапываться.
НС>>Контейнер и есть — service locator. S>Да, я это в примере выше с двумя конструкторами отчетливо показал. Т.е. когда у нас D. Injection мы вообщем-то S>вообще можем не знать про IoC контейнер
Мы сейчас обсуждаем не голый принцип, а контейнеры, я каждый раз явно про это писал. И при обсуждении контейнера мы не можемабстрагироваться от него.
S>(где-то там, а может и вообще нету). А когда у нас SL, то мы завязываемся S>на контейнер.
В случе дотнета — не совсем. Большая часть нормальных фреймворков опираются на System.IServiceProvider, который присутствует в дотнете аккурат с версии 1.0. А поделия боа-бла архитектов, изобретающих свой ISP не вижу смысла обсуждать — если руки из жопы, то руки из жопы.
S> Короче, разница в том, как использовать контейнер -- явно SL, неявно -- DI.
Ну смотри:
class MyService
{
MyService(IServiceProvider provider)
{
var service = provider.GetService(ResolveCustomServiceType(...));
...
}
}
Тут как, явно или неявно?
S>И о чем мне данная сигнатура должна сказать?
О том что разговаривать о штатном DI контейнере дотнета в отрыве от service locator нельзя, это часть его публичного API.
S>Когда мне понадобиться тип TService он будет создан S>Func<IServiceProvider,TImplementation> implementationFactory. Хорошо, и?
И IServiceProvider в сигнатуре не видишь? Я же жерным специально выделил.
Здравствуйте, Sharov, Вы писали:
S>Я не очень понимаю, что получится тогда без этой детали .
Нормально получится. Есть легковесные контейнеры без этой фичи.Разница в основном в поведении на негативных сценариях.
S> Такая себе, краеугольная деталь.
Почему краеугольная? Еще раз спрашиваю — что за ключевой функционал DI контейнеров нельзя реализовать без явного построения и анализа графа зависимостей?
Здравствуйте, Ночной Смотрящий, Вы писали:
S>> Короче, разница в том, как использовать контейнер -- явно SL, неявно -- DI. НС>Ну смотри: НС>
НС>class MyService
НС>{
НС> MyService(IServiceProvider provider)
НС> {
НС> var service = provider.GetService(ResolveCustomServiceType(...));
НС> ...
НС> }
НС>}
НС>
НС>Тут как, явно или неявно?
Явная, конечно. Была бы неявная, если бы параметром конструктора был CustomServiceType.
S>>И о чем мне данная сигнатура должна сказать? НС>О том что разговаривать о штатном DI контейнере дотнета в отрыве от service locator нельзя, это часть его публичного API.
Разумеется нельзя, если это по сути один и тот же объект. Вся разница в его употреблении.
В примере выше у нас контейнер как SL, если убрать зависимость от контейнера в параметре -- у нас DI.
Которая тем же контейнером, но без нашего участия, отменно сконфигурирует (разрешит все зависимости)
для конструируемого объекта.
Здравствуйте, Sharov, Вы писали:
S>Явная, конечно.
Почему? Типов DI контейнера в коде нет.
S> Была бы неявная, если бы параметром конструктора был CustomServiceType.
А если CustomServiceType неизвестен на этапе компиляции?
S>>>И о чем мне данная сигнатура должна сказать? НС>>О том что разговаривать о штатном DI контейнере дотнета в отрыве от service locator нельзя, это часть его публичного API. S>Разумеется нельзя, если это по сути один и тот же объект.
Бинго! Теперь возвращаемся в начало. Как в таком разе IncrementTop умудляется противопоставлять service locator и DI контейнер?
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Явная, конечно. НС>Почему? Типов DI контейнера в коде нет.
Типов нет, интерфейс есть.
S>> Была бы неявная, если бы параметром конструктора был CustomServiceType. НС>А если CustomServiceType неизвестен на этапе компиляции?
Значит есть его интерфейс, иначе в коде выше с SL тоже немного смысла.
НС>Бинго! Теперь возвращаемся в начало. Как в таком разе IncrementTop умудляется противопоставлять service locator и DI контейнер?
По способу использования, очевидно -- это одна и та же сущность, которую по разному можно использовать.
S>> Такая себе, краеугольная деталь. НС>Почему краеугольная? Еще раз спрашиваю — что за ключевой функционал DI контейнеров нельзя реализовать без явного построения и анализа графа зависимостей?
У меня в коде операторов new практически нету, разве в Composition Root, как разрешать зависимости конструкторов?
С чего начать.
Здравствуйте, Sharov, Вы писали:
S>>>Явная, конечно. НС>>Почему? Типов DI контейнера в коде нет. S>Типов нет, интерфейс есть.
Интерейс это тоже тип. Поэтому интерфейсов тоже нет.
S>>> Была бы неявная, если бы параметром конструктора был CustomServiceType. НС>>А если CustomServiceType неизвестен на этапе компиляции? S>Значит есть его интерфейс
Нету. Есть только базовый интерфейс.
S>, иначе в коде выше с SL тоже немного смысла.
Достаточно там смысла. Конкретно в контейнере МС нет возможности зарегистрировать две реализации одного интерфейса одновременно (есть AddEnumerable, но там тоже свои ограничения). В таких ситуациях в контейнере регистрируется именно реализация, а интерфейс внутрь контейнера не лезет. И код подобный приведенному внутри библиотек вполне себе встречается.
НС>>Бинго! Теперь возвращаемся в начало. Как в таком разе IncrementTop умудляется противопоставлять service locator и DI контейнер? S>По способу использования, очевидно
Нет, не очевидно.
S> -- это одна и та же сущность, которую по разному можно использовать.
Пошли по кругу. Еще раз — DI контейнер это частный случай service locator, он строго соответствует определению этого термина, без оговорок. Поэтому противопоставлять SL и DI контейнер ни в каком контексте нельзя, это логически некорректно.
Здравствуйте, Sharov, Вы писали:
S>У меня в коде операторов new практически нету,
Как это связано с графом зависимостей?
S> разве в Composition Root, как разрешать зависимости конструкторов?
Зачем для этого граф? DI просто заменяет явный вызов ресолва сервиса на неявный, ориентируясь на сигнатуру ктора, методов или набор свойств. Каким боком тут нужен граф зависимостей? Ты этот вопрос уже три раза проигнорировал. Если нет ответа — так и скажи.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Интерейс это тоже тип. Поэтому интерфейсов тоже нет.
Тогда это не скомпилируется. Иначе хотелось бы увидеть пример.
S>>Значит есть его интерфейс НС>Нету. Есть только базовый интерфейс.
А интерфейс, как мы знаем, тоже тип. И зачем нам зависить от лишнего типа?
S>>, иначе в коде выше с SL тоже немного смысла. НС>Достаточно там смысла. Конкретно в контейнере МС нет возможности зарегистрировать две реализации одного интерфейса одновременно (есть AddEnumerable, но там тоже свои ограничения). В таких ситуациях в контейнере регистрируется именно реализация, а интерфейс внутрь контейнера не лезет. И код подобный приведенному внутри библиотек вполне себе встречается.
Возможно, контейнеры разные бывают.
НС>Нет, не очевидно.
Очень жаль
S>> -- это одна и та же сущность, которую по разному можно использовать. НС>Пошли по кругу. Еще раз — DI контейнер это частный случай service locator, он строго соответствует определению этого термина, без оговорок. Поэтому противопоставлять SL и DI контейнер ни в каком контексте нельзя, это логически некорректно.
Можно какой-нибудь содержательный интерент источник, где бы это утверждалось или обосновывалось? Мне
они видятся довольно параллельными подходами. Фундаментально параллельными, что аж SL нонче считаю антипаттерном.