Какова причина отсутствия такой перегрузки?
Прежде всего, потому что, (как сказал Эрик Липперт :
никто никогда не проектировал, не определял, не реализовывал, не тестировал, не документировал и не поставлял эту функцию Все шесть из этих вещей необходимы для реализации какой-либо функции. Все они стоят
Во-вторых, перегрузки Collection.Register
, которые принимают список Type
экземпляров (например, Collection.Register<TService>(params Type[])
), принимают список как реализаций, так и абстракций. Предоставление Lifestyle
для абстракций не имеет большого смысла и даже сбивает с толку.
Чтобы понять, почему Simple Injector позволяет предоставлять абстракции, взгляните на следующую регистрацию:
container.Collection.Register<ILogger>(
typeof(ILogger),
typeof(ISpecialLogger),
typeof(SqlLogger));
container.Register<ILogger, DefaultLogger>(Lifestyle.Scoped);
container.Register<ISpecialLogger, SpecialLogger>(Lifestyle.Singleton);
В этом примере регистрируется коллекция регистраторов, где два из предоставленных типов являются абстракциями. Идея, позволяющая предоставлять абстракции, заключается в том, что вы можете указать им другие регистрации. Это именно то, что делает предыдущий пример. При разрешении коллекции регистраторов она будет состоять из Scoped
DefaultLogger
, Singleton
SpecialLogger
и Transient
SqlLogger
.
.
Теперь рассмотрим гипотетическую новую Collection.Register
перегрузку, которая принимает Lifestyle
:
container.Collection.Register<ILogger>(new[]
{
typeof(ILogger),
typeof(ISpecialLogger),
typeof(SqlLogger)
},
Lifestyle.Transient);
container.Register<ILogger, DefaultLogger>(Lifestyle.Scoped);
container.Register<ISpecialLogger, SpecialLogger>(Lifestyle.Singleton);
Что означает, что все элементы Transient
, тогда как два элемента указывают на регистрацию разных стилей жизни?
Мы не нашли хорошего API, который бы решал эти проблемы (пока), поэтому у контейнера отсутствует такая перегрузка.
Каков предпочтительный способ добавления коллекции, где все элементы должны иметь стиль жизни, который не является образом жизни по умолчанию?
Есть несколько способов сделать это.
Вариант 1: зарегистрировать элемент явно
Коллекции, зарегистрированные в Simple Injector, используют запасной механизм для определения своего образа жизни. Это делается путем проверки, существует ли конкретная регистрация для элемента коллекции. Например:
container.Collection.Register<ILogger>(typeof(SqlLogger), typeof(FileLogger));
// Ensures that SqlLogger is a Singleton when part of the IEnumerable<ILogger>.
container.Register<SqlLogger>(Lifestyle.Singleton);
Когда IEnumerable<ILogger>
впервые разрешается с помощью простого инжектора, для каждого элемента он будет (в следующем порядке):
- Попробуйте получить явно зарегистрированную конкретную регистрацию (в примере:
Register<SqlLogger>
- Попробуйте получить эту регистрацию, используя разрешение незарегистрированного типа
- Попробуйте создать саму регистрацию при использовании настроенного
Container.Options.LifestyleSelectionBehavior
(по умолчанию Transient
).
Вариант 2. Использование перегрузки Register (Type, IEnumerable )
Вместо предоставления списка типов или сборок для Collection.Register
, вы также можете предоставить список Registration
экземпляров. A Registration
описывает создание определенного компонента для определенного образа жизни, и этот класс используется Simple Injection для внутреннего использования, когда вы звоните Container.Register
или Container.Collection.Register
. Но вы также можете создавать Registration
экземпляры вручную и передавать их на перегрузку Collection.Register
следующим образом:
// Load the list of types without registering them
Type[] types = container.GetTypesToRegister<ILogger>(assemblies);
// Register them using the overload that takes in a list of Registrations
container.Collection.Register<ILogger>(
from type in types
select Lifestyle.Transient.CreateRegistration(type, container));
Это заставляет все зарегистрированные типы коллекции вести образ жизни Transient
. Вы также можете назначить каждому типу свой собственный образ жизни, если хотите.
Вариант 3: переопределить стиль жизни, выбор поведения
Если регистрация не может быть найдена, Collection.Register
сама регистрируется в последнюю минуту, используя настроенный LifestyleSelectionBehavior
. Поведение выбора по умолчанию всегда возвращает Lifestyle.Transient
, но это поведение можно изменить. Например:
class CustomLifestyleSelectionBehavior : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type implementationType) =>
implementationType == typeof(SqlLogger)
? Lifestyle.Singleton
: Lifestyle.Transient;
}
Эта реализация, если, очевидно, немного наивна, но показывает концепцию. Вы можете переопределить поведение по умолчанию следующим образом:
container.Options.LifestyleSelectionBehavior =
new CustomLifestyleSelectionBehavior();
Вариант 4: Добавить
Рядом с Collection.Register
, который позволяет регистрировать все элементы за один раз, вы можете использовать методы Collection.Append
. Они позволяют поочередно регистрировать элементы коллекции:
container.Collection.Append<ILogger, SqlLogger>(Lifestyle.Singleton);
container.Collection.Append<ILogger, FileLogger>(Lifestyle.Transient);
Доступны также неуниверсальные перегрузки, которые упрощают автоматическую регистрацию этих типов, например, при возврате с использованием Container.GetTypesToRegister
.
Это ваши основные опции в Simple Injector v4.6. Мы могли бы решить добавить удобную перегрузку Collection.Register<T>(IEnumerable<Type>, Lifestyle)
в будущем, так как пропуск этой перегрузки время от времени вызывает некоторую путаницу.