2

我已经搜索过这个问题,但没有运气。开始了。

假设我有一个接口:

interface IQueryRepository<T> where T : class

我想绑定任何请求:

IQueryRepository<IClient>

到:

ConcreteQueryRepository<Client>

我已经尝试了明显的:

Bind<IGenericQueryRepository<IClient>>().To<ConcreteQueryRepository<Client>>()

但我收到一个错误:

ConcreteQueryRepository<Client>不能在泛型类型或方法“ Ninject.Syntax.IBindingToSyntax<T>.To<TImplementation>()”中用作类型参数“TImplementation”没有从“ ConcreteQueryRepository<Client>”到“ IGenericQueryRepository<IClient>”的隐式引用转换

但我不明白为什么因为 GenericQueryRepository 实现了 IGenericQueryRepository 而 Client 实现了 IClient。

我希望 Ninject 给我一个具体的通用存储库,其中 T 是客户端。我希望这避免在代码中使用具体类型。

可以做到吗?

4

2 回答 2

4

这与协方差和逆变有关

在您的问题中,您提到了以下内容:

... GenericQueryRepository 实现 IGenericQueryRepository 和 Client 实现 IClient。

让我们通过使用 fruits 来简化:Fruit 实现了 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,但 Fruit Tree 并没有实现 IFruit Tree。Fruit Tree 和 IFruit Tree 之间没有演员表,尽管你会预料到。它们都是树,但具有不同的类型参数。它们的类型参数彼此相关的事实并不重要。

换句话说:Fruit Tree 和 IFruit Tree 之间不可能进行强制转换,因为它们的类型参数不匹配。

通常,在使用泛型进行强制转换时,请确保它们的类型参数匹配。但是,也有一些例外情况。请参阅泛型接口中的差异

在您的情况下,您可以通过使用 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
    }
}

这应该弄清楚什么是可能的,什么是不可能的。

于 2012-09-12T13:16:47.867 回答
1

我在尝试将 Dapper 查询绑定到接口类型时遇到了同样的问题,考虑一下,Dapper 无法实例化接口类型似乎是有道理的。

接口只是一个契约,不知道如何实例化它的具体实现。

Dapper 需要一个接口类型的具体实现类型,否则 Dapper 还必须知道要实例化接口的哪个具体实现,在这种情况下,Dapper 的行为就像一个 DI 容器,实际上它不是。

于 2014-09-05T02:25:04.333 回答