鉴于以下简化的接口/类结构,我无法使用 Ninject 加载我的泛型类型实现。
public interface IEntry {}
public class TestEntry : IEntry {}
public interface IDBConnection<T> {}
public class DBConnection<T> : IDBConnection<T> where T : IEntry {}
我在加载的 NinjectModule 中使用绑定:
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<>)).To(typeof(DBConnection<>));
我想DBConnection<TestEntry>通过以下调用获取一个实例:
Kernel.TryGet<IDBConnection<IEntry>>();
然而,这只是返回一个开放的实例类型;如果我将 Kernel.Get 调用更改为DBConnection<IEntry>:DBConnection<TestEntry>
Kernel.TryGet<IDBConnection<TestEntry>>();
我知道泛型是不变的,但如果我需要规定我的泛型类的实现以便 Ninject 加载它,我们似乎绕过了 DI/IOC 的全部目的......所以我必须要么绑定,要么获取或理解事情不正确。
此外,我尝试了一种不同的绑定/加载方法:
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
和
Kernel.TryGet<IDBConnection<IEntry>>();
但是,这会产生异常:
System.InvalidCastException:无法转换类型为“DBConnection
1[TestEntry]' to type 'IDBConnection1 [IEntry]”的对象。
这是因为泛型类型IDBConnection<IEntry>不是协变的DBConnection<TestEntry>吗?
我希望能够在DBConnection<TestEntry>我IDBConnection<IEntry>的消费声明中注入 Ninject;但是泛型的不变性似乎不允许这样做。解决方案是什么?
编辑:这是一个单元测试来演示/解释
    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);
    }