Ninject:如何将泛型类型动态注入到绑定模板对象中

Ninject: How To Dynamically Inject Generic Type into Bound Template Object

我在 Ninject 配置中配置了一个通用模板 class。

模板Class:

public Repository<T> : IRepository<T>
{
    //...
}

Ninject 配置:

container.Bind(typeof(IRepository<>)).To(typeof(Repository<>));

此外,我有一个class需要动态创建IRepository<T>的多个实例,其中T对于每个实例都是动态的。

有没有办法用 Ninject 做到这一点?伪代码如下:

foreach(Type genericType in repositoryTypes)
{
    var tempRepository = WebManager.Get(IRepository<genericType>); //how should this actually be?

    //do stuff with tempRepository
}

WebManager 会像下面这样:

public static class WebManager 
{
    public static object Get(Type t)
    {
        object service = GlobalConfiguration.Configuration.DependencyResolver.GetService(t);
        return service;
    }
}

当然可以,很简单:

foreach(Type genericType in repositoryTypes)
{
    object tempRepository = WebManager.Get(typeof(IRepository).MakeGenericType(genericType));
    //do stuff with tempRepository
}

但接下来会变得更加棘手。你将如何使用这个 object?你需要使用反射。使用一次比每次调用更简单。所以我们可以adjust/write代码如下:

internal class Foo
{
    private static readonly MethodInfo DoStuffToRepositoryForMethod =
        typeof(Foo).GetMethod(
            "DoStuffToRepositoryFor",
            BindingFlags.Instance | BindingFlags.NonPublic);

    private readonly IResolutionRoot resolutionRoot;

    public Foo(IResolutionRoot resolutionRoot)
    {
        this.resolutionRoot = resolutionRoot;
    }

    public void DoStuffToRepositories(params Type[] entityTypes)
    {
        foreach (Type entityType in entityTypes)
        {
            MethodInfo doStuffMethod = DoStuffToRepositoryForMethod
                .MakeGenericMethod(entityType);
            doStuffMethod.Invoke(this, new object[0]);
        }
    }

    private void DoStuffToRepositoryFor<T>()
    {
        var repository = this.resolutionRoot.Get<IRepository<T>>();
        repository.DoSomething();
    }
}

仅供参考,这是一个表明它有效的测试:

public class Test
{
    [Fact]
    public void TestIt()
    {
        var kernel = new StandardKernel();
        kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));

        var foo = kernel.Get<Foo>();

        foo.DoStuffToRepositories(typeof(string), typeof(int));
    }
}

如无必要,请不要使用魔法

但我认为更重要的问题是:你为什么要这样做? 您如何知道实体类型列表和要为其做某事的实体? 在大多数情况下,有一种替代方法不涉及那么多 "magic".