4

私には2つのインターフェースがあり、そのうちの1つはジェネリックであり、2番目のインターフェースから派生したタイプのみを許可します。彼らはこのように見えます:

public interface IProvider<T> where T : IContent
{
    T getContent(int i);
    void addContent(T content);
}
public interface IContent
{
    string whatIAm();
}

もちろん、私の実際のインターフェースはもっと複雑ですが、私の問題が何であるかを示すには十分です。今、私は各インターフェースに具体的なクラスを持っています:

public class Provider : IProvider<FileContent> 
{
    public FileContent getContent(int i)
    {
        return null;
    }
    public void addContent(FileContent content)
    {
    }
}

public class FileContent : IContent{
    public string whatIAm(){
        return "FileContent";
    }
}

そして私のコードでは、参照タイプ「IProvider」を使用したいのですが、キャストがうまくいきません...この例を見てください:

 static void Main(string[] args)
    {
        Provider p = new Provider(); //works
        IProvider<FileContent> pp = p as IProvider<FileContent>; //also works
        IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :(
    }

ppp常にnullです。このキャストが機能していることを変更するにはどうすればよいですか?前もって感謝します。

4

3 に答える 3

6

型引数は正確に一致する必要があります。IProvider<IContent>は とは異なる型でIProvider<FileContent>あり、それらの間に継承はありません。

IProvider<IContent> ppp  あなたがfromを持っていてIProvider<FileContent>、開発者が を試すと想像してくださいppp.addContent(someOtherContentThatIsNoFileContent)。そのステートメントは に対して有効ですがIProvider<IContent>、型の安全性が損なわれるため、そのような変換を許可しないのが正しいことです。 

ジェネリック型パラメーターの共変性と反変性は、特定の状況下でこのようなことを許可しますが、インターフェイスは型パラメーターを入力パラメーターと出力パラメーターの両方として使用するため、現在宣言されている方法には適用されません。

編集:IEnumerableの定義を見てください:

public interface IEnumerable<out T> 

したがって、IEnumerable は出力パラメーターとしてのみ使用することがわかりT(項目を追加することはできず、それらを列挙することしかできません)、outキーワードはそれTが共変であることを指定します。だからあなたはすることができます

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

これを行いたい場合はadd、インターフェイスからメソッドを削除する必要があります。in入力パラメーターとジェネリック型パラメーター のキーワードにも同じことが当てはまります。

インターフェイスは次のようになります。

public interface IProvider<out T> where T : IContent
{
    T getContent(int i);
}
于 2012-07-17T12:39:57.750 に答える
3

これは、C#で一般的に機能する方法ではありません。のジェネリックはIProvider<FileContent>のサブタイプではありませんIProvider<IContent>

于 2012-07-17T12:34:27.473 に答える
1

あなたが書いた

Provider p = new Provider(); //works
IProvider<FileContent> pp = p as IProvider<FileContent>; //also works
IProvider<IContent> ppp = pp as IProvider<IContent>; //fails :(

これら3つすべてが機能すると仮定しましょう。すると、次のように書けるようになります。

ppp.addContent(new NonFileContent());

whereは を実装しているが、 から派生していないNonFileContentクラスです。IContentFileContent

ここで、次の呼び出しで何が起こるか想像してみてください。

FileContent fc = pp.getContent(0);

追加されたばかりのオブジェクトが返されるはずです。ただし、NonFileContentインスタンスではなく、FileContentインスタンスです。したがって、戻り値がインスタンスでなければならないメソッドからこのオブジェクトを返すことは不可能です。そのため、コンパイラはそもそも代入互換性を考慮しFileContentません。ppppp

于 2012-07-17T12:46:08.280 に答える