7

IEnumerableC# 4.0 には共変パラメーターがあるため、次のコードでどのように動作しているか混乱しています。

public class Test
{
    IEnumerable<IFoo> foos;

    public void DoTestOne<H>(IEnumerable<H> bars) where H : IFoo
    {
        foos = bars;
    }

    public void DoTestTwo(IEnumerable<IBar> bars)
    {
        foos = bars;
    }
}
public interface IFoo
{
}
public interface IBar : IFoo
{
}

したがって、基本的にDoTestOneメソッドはコンパイルされませんが、コンパイルされますDoTestTwo。うまくいかない理由に加えて、 ( をにDoTestOne割り当てる)効果を達成する方法を誰かが知っていれば、助けていただければ幸いです。IEnumberable<H> where H : IFooIEnumberable<IFoo>

4

4 に答える 4

10

H がクラスになることがわかっている場合、これは機能します。

    public void DoTestOne<H>(IEnumerable<H> bars) where H : class, IFoo
    {
        foos = bars;
    }

ここでの問題は、H が値型の場合、ボックス化されたインスタンスを返さなければならないIEnumerable<MyStruct>のに対し、実際には値型を返すため、共分散が期待どおりにならないことです。IEnumerable<IFoo>必要に応じて、これを回避するために明示的に使用できますCast<IFoo>

于 2012-10-18T19:42:56.227 に答える
3

そこにキャストするだけですIEnumerable<IFoo>

public void DoTestOne<H>(IEnumerable<H> bars) where H : IFoo
{
    foos = (IEnumerable<IFoo>)bars;
}

Dan Bryant の厚意により編集foos = bars.Cast<IFoo>():上記の代わりに使用するHと、 がstruct.

于 2012-10-18T19:41:06.573 に答える
1

.net ランタイム内では、すべての値の型に同じ名前の関連付けられたヒープ オブジェクト型があります。一部のコンテキストでは、値の型が使用されます。他のコンテキストでは、ヒープ タイプ。値型の格納場所 (変数、パラメータ、戻り値、フィールド、または配列スロット) が宣言されると、その格納場所はその型の実際の内容を保持します。クラス型の格納場所が宣言されると、それは、nullまたは別の場所に格納されているヒープ オブジェクトへの参照を保持します。インターフェイス型の格納場所は、参照型の格納場所のように扱われ、インターフェイスの実装の一部 (またはすべて) が実際には値型であっても、ヒープ参照を保持します。

値の型を参照型の格納場所に格納しようとすると、システムはその値の型に関連付けられたヒープ型の新しいインスタンスを作成し、すべてのフィールドを元の格納場所から新しいインスタンスの対応するフィールドにコピーします。そのインスタンスへの参照を保存します。これは「ボクシング」と呼ばれるプロセスです。ヒープ参照を値型の格納場所にキャストしようとすると、値型に関連付けられたヒープ型のインスタンスを参照しているかどうかがチェックされます。その場合、ヒープ オブジェクトのフィールドは、値型の格納場所にある対応するフィールドにコピー (「ボックス化解除」) されます。

のような型がSystem.Int32から派生したように見えるかもしれませんがSystem.Object、それは半分しか当てはまりません。System.Int32から派生したヒープオブジェクト type がありSystem.Objectますが、 type の変数はSystem.Int32そのようなオブジェクトへの参照を保持しません。代わりに、そのような変数は、その整数に関連付けられた実際のデータを保持します。データ自体は単なるビットの集まりであり、何からも派生していません

インターフェイス型の格納場所を「インターフェイス_を実装する System.Object から派生したもの」を保持していると考えると、そのインターフェイスを実装する任意のクラス型のインスタンスはその型のインスタンスですが、値型のインスタンスであっても、それらが他の型に変換可能である場合、他の型のインスタンスではありません。を使用するコードは、そのメソッドが、または implementsに変換できるものを返すことIEnumerator<IFoo>だけを望んでいません。そのimplementsの派生物である何かを返すことを望んでいます。したがって、 をに置き換えるには、両方を実装するように制約する必要があります。CurrentIFooIFooObjectIFooIEnumerable<T>IEnumerable<IFoo>TIFooと の適切な導関数になりSystem.Objectます。

于 2012-10-18T22:22:43.047 に答える
0

戻り値のキャストまたはジェネリック制約の「クラス」識別子を忘れました。あなたのやっていることはもちろん可能です。以下を参照してください。

から: http://msdn.microsoft.com/en-us/library/d5x73970.aspx

where T : <interface name>

The type argument must be or implement the specified interface.
Multiple interface constraints can be specified. The constraining interface can also be generic.
于 2012-10-18T19:44:50.877 に答える