C# Ninject-管理泛型类型的差异?

C# Ninject-管理泛型类型的差异?,c#,generics,dependency-injection,ninject,dependency-management,C#,Generics,Dependency Injection,Ninject,Dependency Management,鉴于以下简化的接口/类结构,我在使用Ninject加载泛型类型实现时遇到困难 public interface IEntry {} public class TestEntry : IEntry {} public interface IDBConnection<T> {} public class DBConnection<T> : IDBConnection<T> where T : IEntry {} Ninject将始终返回您要求的类型。如果您

鉴于以下简化的接口/类结构,我在使用Ninject加载泛型类型实现时遇到困难

public interface IEntry {}

public class TestEntry : IEntry {}

public interface IDBConnection<T> {}

public class DBConnection<T> : IDBConnection<T> where T : IEntry {}

Ninject将始终返回您要求的类型。如果您请求
IDBConnection
,那么如果您请求
IDBConnection
,您将得到该类型。没有超级逻辑可以分析你的代码,让你得到一个不同于你所要求的类型

但是直接请求IDBConnection之类的东西是使用Ninject的错误方式。您应该使用构造函数注入来注入它:

 public class NeedDbConnection<T> {
      public NeedDbConnection(IDBConnection<T> connection) { ... } 
 }
公共类NeedDbConnection{
公共需要的数据库连接(IDBConnection连接){…}
}

这样,您就可以获得适合该类的特定db连接。

条目是否为域对象?我很少看到人们让他们的域对象实现接口的例子;我假设您也没有看到模板化域对象的示例?但是,如果模型类没有实现接口,则泛型中的子/父类是非子午的问题仍然存在。C#/Ninject不能对泛型使用协方差(对吗?)。似乎泛型和DI不能很好地结合在一起,因为不可避免地需要硬编码一个实现类ala-IKernel.TryGet()因此首先否定了DI/IOC的目的。这种设计背后的驱动力是MongoDB C#驱动程序,它是嵌入式的,并且严重依赖于模板域对象-可以在下面看到一些示例:[您将拥有多个IEntry实现吗?如果是,那么在检索IDBConnection时指定条目类型才有意义。如果不是:IDBConnection是修复的还是可以更改它的差异?如果不能,您将陷入困境。使用一个简单的IDBConnection接口如何,该接口具有泛型类型方法检索,其中TEntry:IEntry等等?我添加了一个单元测试来演示这个问题。@BatteryBackupUnit感谢您提出的支持泛型类而支持泛型方法的建议;现在就开始研究这个问题。虽然它确实简化了注入,但缺点是消费者调用有额外的责任来规定类型(在实例化之后不应该更改:/)棘手的一点是作为泛型类型param的模型类的接口。我重构了它,实现更直接。如果ninject能够处理从泛型参数实现绑定/获取泛型参数接口,那将是一件好事,但我知道这只是一个不一致的限制。
Kernel.TryGet<IDBConnection<IEntry>>();
Kernel.TryGet<IDBConnection<TestEntry>>();
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
Kernel.TryGet<IDBConnection<IEntry>>();
    public interface IEntry { }

    public class TestEntry : IEntry { }

    public interface IDBConnection<T> where T : IEntry { }

    public class DBConnection<T> : IDBConnection<T> where T : IEntry { }

    class TestModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IEntry>().To<TestEntry>();
            Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
        }
    }

    [Test]
    public void NinjectGenericLoadTest()
    {
        /// this loads the expected type from interfaces however is useless
        /// since loaded against a "var" 
        ///(runtime casts knowing the impl would be required to use)
        StandardKernel kernel = new StandardKernel(new TestModule());
        var ninjected = kernel.TryGet(typeof(IDBConnection<IEntry>));
        Assert.IsInstanceOf<DBConnection<TestEntry>>(ninjected);

        /// The following is what I want but it won't compile 
        ///:"Cannot implicitly convert type 'object' to 
        ///'EasyMongo.Contract.IReader<EasyMongo.Contract.IEasyMongoEntry>'. 
        /// An explicit conversion exists (are you missing a cast?)"
        //kernel = new StandardKernel(new TestModule());
        //IDBConnection<IEntry> ninjectedInterface = kernel.TryGet(typeof(IDBConnection<IEntry>));
        //Assert.IsInstanceOf<DBConnection<Entry>>(ninjectedInterface);

        /// this throws System.InvalidCastException : Unable to cast object of type 
        /// 'DBConnection`1[EasyMongo.Test.Base.RandomTest+Entry]' 
        /// to type 'IDBConnection`1[EasyMongo.Test.Base.RandomTest+IEntry]'.
        /// this is due to incovariance of generic types such that DBConnection<Entry> 
        /// is not a IDBConnection<IEntry> 
        IDBConnection<IEntry> ninjectedInterface = (IDBConnection<IEntry>)kernel.TryGet(typeof(IDBConnection<IEntry>));
        Assert.IsInstanceOf<DBConnection<TestEntry>>(ninjectedInterface);
    }
 public class NeedDbConnection<T> {
      public NeedDbConnection(IDBConnection<T> connection) { ... } 
 }