2013-07-30 30 views
8

コンテキスト:.NET 4.0、C#C#ジェネリックスとインターフェイスの実装を使用

私はいくつかのサービスを提供するためにそれらを実装する一連のインターフェイスと一連のクラスを作成しています。クライアントは具体的なクラスを使用しますが、インターフェイスをパラメータ型として宣言したメソッドを呼び出します。

簡略化した例はこの1つである:

namespace TestGenerics 
{ 
    // Interface, of fields 
    interface IField 
    { 
    } 

    // Interface: Forms (contains fields) 
    interface IForm<T> where T : IField 
    { 

    } 

    // CONCRETE CLASES 
    class Field : IField 
    { 
    } 

    class Form <T> : IForm<T> where T : IField 
    { 
    } 

    // TEST PROGRAM 
    class Program 
    { 
     // THIS IS THE SIGNATURE OF THE METHOD I WANT TO CALL 
     // parameters are causing the error. 
     public static void TestMethod(IForm<IField> form) 
     { 
      int i = 1; 
      i = i * 5; 
     } 

     static void Main(string[] args) 
     { 
      Form<Field> b = new Form<Field>(); 
      Program.TestMethod(b); 
     } 
    } 
} 

コードは、私には理にかなって、私は、コンパイラのエラーを取得:

Argument 1: cannot convert from ' TestGenerics.Form<TestGenerics.Field> ' to ' TestGenerics.IForm<TestGenerics.IField> ' TestGenerics

私は私が間違ってやっているかわからないんだけど私はインターネット上の多くのページを読んだが、誰も私の問題を解決しなかった。

はそれほど私が構築しようとしているかのアーキテクチャを変更しないと解決策はあります:

編集:私は、彼らがそれらを実装する具体的なclasesの独立していなければならないような方法でインタフェースを設計し。コンクリートのclaseはdllから読み込むことができますが、ほとんどのアプリケーションはインターフェイスで動作します。場合によっては、具体的なクラスを使用する必要があります。特に、直列化が必要なクラスを使用する場合には必要です。

ありがとうございます。

アレハンドロ

+5

public interface IForm { IEnumerable<IField> Fields { get; set; } } 

。具体的には、['out'ジェネリック修飾子](http://msdn.microsoft.com/en-us/library/dd469487.aspx)をあなたの署名' interface IForm T:IField'に追加すると動作します。しかし、これは他の制限/考慮事項を追加するので、あなたの現在の設計/使用に該当するかどうかはコメントできません。 –

+2

私はこのデザインで何を達成しようとしているのか不思議です。 – sidesinger

+0

両方のアンワに対しておかげさまで、本当に親切でした。私はなぜそのように解決策を検討したのかを説明する編集を追加しましたが、両方の問題が私の問題を解決することができます。敬具。 – Sugar

答えて

13

問題はForm<Field>IForm<Field>なくIForm<IField>を実装していることです。継承されたクラス(またはインターフェース)は、out識別子と共変変数としてマークされていない限り、汎用パラメーターとして使用することはできません。ただし、インターフェイスを共変変数としてマークすると、使用方法が大幅に制限されます(基本的には出力専用インターフェイス(IEnumerableなど))ので、うまく動作しない可能性があります。仕事にそれを得るために

一つの方法は、同様にTestMethodは一般的なようにすることです:

public static void TestMethod<T>(IForm<T> form) where T:IField 
{ 
    int i = 1; 
    i = i * 5; 
} 
10

あなたがそうのように、共分散を使用することができます:共変性と反変性hereについて

interface IForm<out T> where T : IField 
{ 

} 

より。

+1

"out"キーワードを使用して派生クラスをジェネリック型パラメータとして使用できるようにする場合の共分散。 IEnumerable インターフェイスの型パラメータが共変であるため、(Visual BasicではIEnumerable(Of Derived))のインスタンスをIEnumerable型の変数に割り当てることができるため、この文を表示するリンクに「 」というメッセージが表示されます。 " –

7

他にも、エラーメッセージの背後にある理由が指摘されていますが、サンプルコードの設計をしばらく調べてみましょう。おそらく、必要のない場所でジェネリックを使用しているのかもしれません。

IFieldインターフェイスで宣言されたメソッドを使用していると言われているので、IFormクラスを汎用的にする必要はありません。単に汎用引数 'T'ではなくIFieldへの参照を格納しますとにかくIFieldであることが既に保証されています)。

例えば

、使用:これは、共分散の領域の下に下落するだろう代わりに

public interface IForm<T> where T : IField 
{ 
    IEnumerable<T> Fields { get; set; } 
} 
+0

合意。別の指示は、消費者コードがこれをIForm とフォームという形式でインスタンス化し、IFieldで十分であることを示しています。真のテストは、具体的なタイプTが外部に面するAPIの一部である必要があるかどうかには関係ありません。 – Tormod

関連する問題