为通用类型实现 ninject 提供程序

Implementing ninject provider for a generic type

使用 ninject,我想为 MyRepository class 创建一个提供程序,它依赖于 ApplicationDbContext:

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

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

    // ...
}

我看到 this document 解释了应该如何创建提供者,但我不确定:

  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 完成此操作吗?


注意:我已经创建 this code review 解释为什么我需要提供者。

因为在这种情况下目标实现类型是提供者已知的。

然后您可以从所请求的类型中获取通用类型,并使用它来构造所需的实现。

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 是假设实现具有原始示例中的代码所暗示的 public 构造函数。如果不是 public 则可以使用反射来查找构造并调用它。

提供者已在内核中注册

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

告诉内核在解析抽象时使用提供者

IMyRepository<MyEntity> repository = kernel.Get<IMyRepository<MyEntity>>();

我成功地为我的通用类型创建了一个提供者:

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