Реализация поставщика ninject для универсального типа

Используя ninject, я хочу создать поставщика для класса MyRepository, который зависит от класса ApplicationDbContext:

public class MyRepository<TEntity> : IMyRepository<TEntity>
    where TEntity : MyBaseEntity
{
    private ApplicationDbContext _dbContext;

    public MyRepository(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // ...
}

Я видел этот документ что объясняет, как должны создаваться провайдеры, но я не уверен:

  1. Как передать аргумент ApplicationDbConext провайдеру
  2. Как создать экземпляр универсального типа

Вот моя попытка:

public class MyRepositoryProvider : Provider<MyRepository> 
{
    protected override MyRepository CreateInstance(IContext context)
    {
        // how to create a generic instance of type T?
        MyRepository myRepository = new MyRepository<T>(/*need ApplicationDbContext*/);
        return myRepository;
    }
}

Я не уверен, можно ли создать провайдер для универсального типа. Если нет, может ли кто-нибудь показать, как это можно сделать с помощью Factory interface?


Примечание. Я создал этот код обзор, объясняющий, почему мне нужен поставщик.


person Hooman Bahreini    schedule 03.11.2019    source источник


Ответы (2)


Так как в этом случае целевой тип реализации известен провайдеру.

Затем вы можете получить общий тип из запрашиваемого типа и использовать его для создания желаемой реализации.

public class MyRepositoryProvider : IProvider {
    private ApplicationDbContext _applicationDbContext;

    public MyRepositoryProvider(ApplicationDbContext applicationDbContext) {
        _applicationDbContext = applicationDbContext;
    }

    Type Type => typeof(MyRepository<>);

    public object Create(IContext context) {
        var genericArguments = context.GenericArguments; //TEntity
        var genericType = this.Type.MakeGenericType(genericArguments); //MyRepository<TEntity>

        //using reflection to do new MyRepository<TEntity>(_applicationDbContext)
        return Activator.CreateInstance(genericType, _applicationDbContext);
    }
}

Activator используется здесь в предположении, что реализация имеет общедоступный конструктор, как подразумевается кодом в исходном примере. Если не является общедоступным, то можно использовать отражение, чтобы найти конструкцию и вызвать ее.

Провайдер зарегистрирован в ядре

kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
kernel.Bind(typeof(IMyRepository<>)).ToProvider(typeof(MyRepositoryProvider)).InRequestScope();

Что говорит ядру использовать провайдера при разрешении абстракций

IMyRepository<MyEntity> repository = kernel.Get<IMyRepository<MyEntity>>();
person Nkosi    schedule 03.11.2019

Мне удалось создать поставщика для моего универсального типа:

public class MyRepositoryProvider<TEntity> : Provider<IMyRepository<TEntity>>
    where TEntity : MyBaseEntity
{
    private ApplicationDbContext _applicationDbContext;

    public MyRepositoryProvider(ApplicationDbContext applicationDbContext)
    {
        _applicationDbContext = applicationDbContext;
    }

    protected override IMyRepository<TEntity> CreateInstance(IContext context)
    {
        return new MyRepository<TEntity>(_applicationDbContext);
    }
}

А вот так выглядит привязка:

kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
kernel.Bind(typeof(IMyRepository<>)).ToProvider(typeof(MyRepositoryProvider<>)).InRequestScope();
person Hooman Bahreini    schedule 07.11.2019