我搜索过这个问题,但没有运气。我们走了。
假设我有一个界面:
interface IQueryRepository<T> where T : class
我想绑定任何请求:
IQueryRepository<IClient>
为:
ConcreteQueryRepository<Client>
我已经尝试过显而易见的事了:
Bind<IGenericQueryRepository<IClient>>().To<ConcreteQueryRepository<Client>>()
但是我收到了一个错误:
ConcreteQueryRepository<Client>
不能用作类型参数&#39; TImplementation&#39;在 通用类型或方法&#39;Ninject.Syntax.IBindingToSyntax<T>.To<TImplementation>()
&#39; 来自&#39;ConcreteQueryRepository<Client>
&#39;没有隐式参考转化。 到&#39;IGenericQueryRepository<IClient>
&#39;
但我不明白为什么,因为GenericQueryRepository实现了IGenericQueryRepository,而Client实现了IClient。
我希望Ninject给我一个具体的通用存储库,其中T是Client。我希望这可以避免在代码中使用具体类型。
可以吗?
答案 0 :(得分:4)
这与Covariance and Contravariance有关。
在你的问题中,你提到了以下内容:
... GenericQueryRepository实现IGenericQueryRepository,Client实现IClient。
让我们通过使用水果简化:水果实施IFruit。我们还将创建一个Tree类。
public interface IFruit { }
public class Fruit : IFruit { }
public class Tree<T> where T : IFruit { }
Tree<IFruit> tree = new Tree<Fruit>() // error
这将重现您遇到的同类错误。为什么?简单。
虽然Fruit实施了IFruit,但果树并没有实施IFruit树。 Fruit Tree和IFruit Tree之间没有任何演员阵容,尽管你会期待它。它们都是树,但具有不同的类型参数。他们的类型参数彼此相关的事实并不重要。
换句话说:Fruit Tree和IFruit Tree之间没有演员阵容,因为他们的类型参数不匹配。
通常,在使用泛型进行投射时,请确保其类型参数匹配。但是,有一些例外情况。请参阅Variance in Generic Interfaces。
在您的情况下,您可以使用IClient作为GenericQueryRepository类的类型参数来修复它。执行此操作将允许进行转换,因为类型参数匹配。但我不了解您的应用程序架构,因此在您的情况下此修复可能不适用。
编辑:为了更容易理解,请复制粘贴下面的代码并查看编译器的内容。
interface IFruit { }
class Fruit : IFruit { }
interface ITree<T> where T : IFruit { }
class Tree<T> : ITree<T> where T : IFruit { }
class Program
{
static void Main(string[] args)
{
ITree<Fruit> test1 = new Tree<Fruit>(); // compiles: type parameters match
ITree<IFruit> test2 = new Tree<Fruit>(); // fails: type parameters don't match
ITree<Fruit> test3 = new Tree<IFruit>(); // fails: type parameters don't match
ITree<IFruit> test4 = new Tree<IFruit>(); // compiles: type parameters match
IEnumerable<IFruit> test5 = new List<Fruit>(); // compiles: this is one of the exceptional cases
}
}
这应该清楚地了解什么是不可能的东西。
答案 1 :(得分:1)
我在尝试将Dapper查询绑定到接口类型时遇到了同样的问题,考虑到它,似乎Dapper无法实例化接口类型。
接口只是一个契约,不知道如何实例化它的具体实现。
Dapper需要一种类型,它是接口类型的具体实现,否则Dapper也必须知道实例化接口的具体实现,在这种情况下,Dapper的行为就像一个DI容器,实际上它不是