2

私はこの問題を検索しましたが、運がありません。どうぞ。

私がインターフェースを持っているとしましょう:

interface IQueryRepository<T> where T : class

そして、私は以下のリクエストをバインドしたいと思います:

IQueryRepository<IClient>

に:

ConcreteQueryRepository<Client>

私は明白なことを試みました:

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

しかし、エラーが発生します:

ConcreteQueryRepository<Client>ジェネリック型またはメソッドで型パラメーター'TImplementation'として使用することはできません' 'から' 'へのNinject.Syntax.IBindingToSyntax<T>.To<TImplementation>()暗黙の参照変換はありませんConcreteQueryRepository<Client>IGenericQueryRepository<IClient>

しかし、GenericQueryRepositoryがIGenericQueryRepositoryを実装し、ClientがIClientを実装しているため、理由がわかりません。

Ninjectに、Tがクライアントである具体的な汎用リポジトリを提供してもらいたいと思います。コードで具象型を使用しないようにしたいと思います。

できますか?

4

2 に答える 2

4

これは共分散と反分散に関係しています。

あなたの質問では、次のことを述べました。

... GenericQueryRepository は IGenericQueryRepository を実装し、Client は IClient を実装します。

フルーツを使って簡単にしましょう: 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 ツリーを実装していません。当然のことですが、Fruit Tree と IFruit Tree の間でキャストを行うことはできません。どちらもツリーですが、型パラメーターが異なります。それらの型パラメーターが互いに関連しているという事実は重要ではありません。

つまり、型パラメーターが一致しないため、フルーツ ツリーと IFruit ツリーの間で可能なキャストはありません。

一般に、ジェネリックでキャストするときは、それらの型パラメーターが一致していることを確認してください。ただし、いくつかの例外的なケースがあります。ジェネリック インターフェイスの差異を参照してください。

あなたの場合、 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 に答える