鉴于以下简化的接口/类结构,我无法使用 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 'IDBConnection
1 [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);
}