#c# #generics #dependency-injection #simple-injector
#c# #общие #внедрение зависимостей #простой инжектор
Вопрос:
Я пытаюсь получить общий тип аргумента при открытой регистрации без необходимости использования object. Вот фрагмент кода:
container.Register(typeof(IRepository<>),
() => new Repository<object>("connString"),
Lifestyle.Transient);
Итак, в лямбде я хотел бы создать экземпляр репозитория с определенным общим типом вместо использования object.
Ответ №1:
Перегрузки Register
, которые принимают лямбда-выражение, не поддерживают общие. Причина этого в том, что простой инжектор больше не сможет анализировать граф объектов для вас и выполнять какой-либо анализ от вашего имени.
Существует несколько решений, но, вероятно, самое простое — извлечь параметр строки подключения в объект данных и позволить репозиторию зависеть от этого:
public class ConnectionStringSettings
{
public readonly string ConnectionString;
public ConnectionStringSettings(string connectionString) {
this.ConnectionString = connectionString;
}
}
container.RegisterSingleton(new ConnectionStringSettings("constr"));
container.Register(typeof(IRepository<>), typeof(Repository<>));
Другой вариант — зарегистрировать строку подключения напрямую, используя условную регистрацию:
container.RegisterConditional(typeof(string),
Lifestyle.Singleton.CreateRegistration(typeof(string),
() => "constr", container),
c => c.Consumer.ImplementationType.Name == typeof(Repository<>).Name);
Таким образом, вы можете оставить аргумент конструктора как есть. Недостатком является то, что эта регистрация несколько сложнее, и эта условная регистрация работает только со ссылочными типами, такими как строки. Мы могли бы исправить это в версии 4.
Другой вариант — зарегистрировать все реализации явно:
container.Register<IRepository<User>>(() => new Repository<User>("connString"));
container.Register<IRepository<Order>>(() => new Repository<Order>("connString"));
container.Register<IRepository<Asset>>(() => new Repository<Asset>("connString"));
Другой вариант — использовать разрешение незарегистрированного типа:
container.ResolveUnregisteredType = (s, e) =>
{
Type serviceType = e.UnregisteredServiceType;
if (serviceType.IsGenericType amp;amp;
serviceType.GetGenericTypeDefinition() == typeof(IRepository<>))
{
Type implementationType = typeof(Repository<>)
.MakeGenericType(serviceType.GetGenericArguments()[0]);
Registration r = Lifestyle.Transient.CreateRegistration(
serviceType,
() => Activator.CreateInstance(implementationType, "connectionString"),
container);
e.Register(r);
}
};
Еще один вариант — переопределить поведение простого инжектора по умолчанию, когда дело доходит до ввода параметров, но для этого требуется довольно много кода, так что это не то, что я бы обычно советовал.