Внедрение ninject-провайдера для универсального типа - PullRequest
2 голосов
/ 03 ноября 2019

Используя 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 ?


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

Ответы [ 2 ]

1 голос
/ 07 ноября 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();
1 голос
/ 03 ноября 2019

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

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

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>>();
...