Получить общий тип аргумента при открытой регистрации с помощью простого инжектора

#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);
    }
};
  

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