【问题标题】:Using Ninject to bind an interface to multiple implementations unknown at compile time使用 Ninject 将接口绑定到编译时未知的多个实现
【发布时间】:2011-11-25 23:09:29
【问题描述】:

我最近刚开始在我的 ASP.NET MVC 3 应用程序中使用 Ninject (v2.2.0.0)。到目前为止,我对此感到很兴奋,但我遇到了一个我似乎无法弄清楚的情况。

我想做的是将接口绑定到具体实现,并让 Ninject 能够使用工厂(也将向 Ninject 注册)将具体实现注入到构造函数中。问题是我希望我的构造函数引用具体类型,而不是接口。

这是一个例子:

public class SomeInterfaceFactory<T> where T: ISomeInterface, new()
{
    public T CreateInstance()
    {
        // Activation and initialization logic here
    }
}

public interface ISomeInterface 
{
}

public class SomeImplementationA : ISomeInterface
{
    public string PropertyA { get; set; }
}

public class SomeImplementationB : ISomeInterface
{
    public string PropertyB { get; set; }
}


public class Foo 
{
    public Foo(SomeImplementationA implA) 
    {
        Console.WriteLine(implA.PropertyA);
    }
}

public class Bar
{
    public Bar(SomeImplementationB implB)
    {
        Console.WriteLine(implB.PropertyB);
    }
}

在其他地方,我想只使用接口进行绑定:

kernel.Bind<Foo>().ToSelf();
kernel.Bind<Bar>().ToSelf();
kernel.Bind(typeof(SomeInterfaceFactory<>)).ToSelf();
kernel.Bind<ISomeInterface>().To ...something that will create and use the factory

然后,当从 Ninject 请求 Foo 的实例时,它会看到其中一个构造函数参数实现了绑定接口,获取工厂,并实例化正确的具体类型 (SomeImplementationA) 并将其传递给 Foo 的构造函数。

这背后的原因是我将有许多 ISomeInterface 的实现,我宁愿避免必须单独绑定每一个。其中一些实现在编译时可能是未知的。

我尝试使用:

kernel.Bind<ISomeInterface>().ToProvider<SomeProvider>();

提供者根据请求的服务类型检索工厂,然后调用其 CreateInstance 方法,返回具体类型:

public class SomeProvider : Provider<ISomeInterface>
{
    protected override ISomeInterface CreateInstance(IContext context)
    {
        var factory = context.Kernel.Get(typeof(SomeInterfaceFactory<>)
            .MakeGenericType(context.Request.Service));
        var method = factory.GetType().GetMethod("CreateInstance");
        return (ISomeInterface)method.Invoke();
    }
}

但是,我的提供程序从未被调用过。

我很好奇 Ninject 是否可以支持这种情况,如果可以,我会如何解决这个问题。

我希望这些信息足以解释我的情况。请让我知道是否需要进一步详细说明。

谢谢!

【问题讨论】:

    标签: ninject


    【解决方案1】:

    您似乎误解了 ninject 的工作原理。如果您创建 Foo ,它会发现它需要 SomeImplementationA 并会尝试为它创建一个实例。所以你需要为SomeImplementationA而不是ISomeInterface定义一个绑定。

    您的实现也很可能违反了依赖倒置原则,因为您依赖于具体实例而不是抽象。

    一次性注册所有相似类型的解决方案(以及配置 IoC 容器的首选方式)是使用约定配置。请参阅 Ninject.Extensions.Conventions 扩展。

    【讨论】:

      最近更新 更多