MS DI, почему Регистрация Реализации - PullRequest
0 голосов
/ 28 сентября 2019

Чтение в этом документе из MS DI: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0

Стремление понять, почему нам нужны эти опции:

Add{LIFETIME}<{IMPLEMENTATION}>()
Example:
services.AddScoped<MyDep>();

Add{LIFETIME}(new {IMPLEMENTATION})
Examples:
services.AddScoped(new MyDep());
services.AddScoped(new MyDep("A string!"));

Что это дает, делая выше, учитывая, что эти новые классынет реализации интерфейса?Контейнер DI в основном абстрагируется через интерфейс, так что решение слабо связано.

Нужно ли нам это регистрировать.

Также есть какая-нибудь разница ниже?Я думаю, что первого будет достаточно:

serviceCollection.AddScoped(typeof(ICertificateService), typeof(CertificateService));

serviceCollection.AddScoped(ICertificateService, CertificateService);

1 Ответ

2 голосов
/ 28 сентября 2019

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

Если реализации реализуют IDisposable, контейнер автоматически обработает удаление (нет необходимости в using блоках) - первая характеристика.

Если вывам нужно несколько реализаций (либо два разных класса, реализующих один и тот же интерфейс, либо один экземпляр класса, который принимает аргумент конструктора, а другой экземпляр, который этого не делает), вы можете добавить их следующим образом - вторая характеристика.

При желании аргумент конструктора также может быть получен из контейнера, поскольку передается IServiceProvider - третья характеристика.

В списке есть две другие перегрузки, которые могут принимать аргументы;каждый имеет параметр типа, но не передал IServiceProvider - он не имеет автоматического удаления;другой не имеет ни одного - он не имеет автоматического удаления или нескольких реализаций.

Таким образом, вы вводите IEnumerable<MyDep> myDeps, а затем проверяете его следующим образом:

var myDep = myDeps.Single(x => x.ReadOnlyProperty == "A string!");

На практике это было бы полезно, если бы у одного из экземпляров был другой сервис с областью действия (например, DbContext или UserManager), который мог одновременно обрабатываться контейнером.

Часть вашего вопроса была:

Что он дает, делая выше, учитывая, что эти новые классы не имеют реализации интерфейса?

Хотя изначально это не имеет особого смысла (то есть классы, вероятно, могли бы простосоздается при необходимости), шаблон способствует «честности конструктора»:

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

Ссылка: Явная зависимостьes

С другой стороны, если бы методы на MyDep не были виртуальными, их было бы трудно переопределить в макете для модульного тестирования (именно поэтому этот шаблон не так распространен для инъекцийинтерфейсы, где все может быть переопределено подделкой).

Стоит также отметить, что еще одна причина, по которой этот подход не так популярен, это то, что вы привязаны к конкретной реализации во всем приложении - вы простоперемещение ключевого слова new вверх в оркестровку контейнера.( New is Glue )

По вашему последнему вопросу:

Также есть какая-нибудь разница ниже?

Я думаюможет быть, вы имели в виду между этими двумя?

serviceCollection.AddScoped(typeof(ICertificateService), typeof(CertificateService));
serviceCollection.AddScoped<ICertificateService, CertificateService>();

Я полагаю, что второе - это просто способ указать сервис и его реализацию в качестве параметров типа вместо необходимости использовать отражение во время выполнения.Но этого будет недостаточно, поскольку он не будет обрабатывать ситуации, когда тип неизвестен до времени выполнения.

...