2

IEnumerable<T>私は疑問に思っていました、なぜ共変性のフラグだけがあり、反変のフラグoutがないの inですか?

public interface IEnumerable<out T>

out私はこの例で理解することができます:

IEnumerable<string> strings = new List<string>(){"a","b","c"};
IEnumerable<object> objects = strings;

objectはより大きいstringので、コンパイラは次のようなことをうまく行うことを恐れています。

 objects = objects.First().Select(x=>5);// ( we cant insert int to string...)

うまく理解しました。

しかし、IEnumerableを挿入として使用したい場合はどうなりますか?

何かのようなもの :

IEnumerable<object> objects = ...;
IEnumerable<string> strings = objects

だから私はオブジェクトに挿入することもできます...

しかし、問題はないということですIEnumerable<in T>...

私はここで何かが欠けていますか?

4

6 に答える 6

4

に挿入することはできませんIEnumerable。残念ながら、「IInsertable」はありません。

コレクションにアイテムを追加することしかできないことを示すインターフェースはありません。これはinジェネリック型になります。すべてのコレクションインターフェイスでアイテムを取得できるため、in一般的な引数を持つことはできません。

編集

インターフェイスIEnumerable<T>にはゲッターしかないため、そのインターフェイスを使用してコレクションに要素を挿入することはできません。そのため、outの宣言で許可されていIEnumerable<out T>ます。Tこれは、型の値が一方向にのみ進み、「出てくる」ことをコンパイラーに通知します。これにより、一方向での互換性があります。あなたはそれから読んでいるだけなので、あなたはIEnumerable<string>として使うことができます。IEnumerable<object>文字列をオブジェクトとして読み取ることができます。しかし、それに書き込むことはできず、オブジェクトを文字列として渡すこともできませんでした。整数またはその他のタイプの場合があります。

于 2012-05-07T08:46:56.690 に答える
4

Eric Lippertは、C#で共変性と反変性を導入する前に、これに関する一連の投稿を行っています。これは一読の価値があります。

簡単な例は

public class Animal(){
...
}

public class Giraf(){
   public void LookAboveTheClouds(){}
}

IEnumerable<Animal> animals = new list<Animal>{
                                    new Elephant(),
                                    new Tiger(), 
                                    new TinyMouse()};
IEnumerable<Giraf> girafs = animals;

foreach(var giraf in girafs){
   //elephants,tigers and tiny mice does not suuport this
   giraf.LookAboveTheClouds() 
}

言い換えれば、コンパイラがあなたIEnumerable<Animal>をとして安全に使用できることを保証できる方法はありませんIEnumerable<Giraf>。すべてのキリンは動物ですが、すべての動物がキリンであるとは限りません

于 2012-05-07T08:58:09.260 に答える
2

ここではあなたの問題はわかりません。使用するときIEnumerableは挿入できません、そしてそれはあなたがしていることではありません。あなたがやろうとしているのはIEnumerable<string>、の値を割り当てることですがIEnumerable<object>、それは機能しません。IEnumerable<string>型のオブジェクトを割り当てる場合IEnumerble<object>、リスト内のすべてのオブジェクトが文字列型であることを保証することはできません。それができない理由です。

キーワードの共変outインターフェースは、出力が消費部分によって常に理解できることを保証します。つまり、IEnumerable<string>リストにキャストでき、リストをIEnumerable<object>消費string : objectする人はobject処理方法を知っている必要がありますstringが、その逆はできません。

contravariant、inキーワード、interfacesを使用すると、オブジェクトをあまり指定されていないジェネリックにキャストできます。つまり、クラスの実装は反変であるがその逆ではないため、処理方法が必要になるため、IComparer<object>にキャストできます。IComparer<string>IComparer<object>string

詳細はこちら: http: //msdn.microsoft.com/en-us/library/dd799517.aspx

于 2012-05-07T09:03:57.180 に答える
1

私は、safityと入力することは厳密に理解されていると思います。リストにあなたが含まれている場合はどうなります
IEnumerable<object> {"Hello", 2.34d, new MyCoolObject(), enumvalue}か?

ランタイムはこれらの変換をどのように処理する必要がありますか?

string単純なケースの場合は、のオーバーライド(存在する場合)を呼び出すだけで十分ですToString()、フレームワーク設計者はカスタムケースに依存できず、一般的なソリューションを提供する必要があります。

お役に立てれば。

于 2012-05-07T08:46:44.600 に答える
1

コメントですでに述べたように、IEnumerableを使用してコレクションを変更することはできません。

オブジェクトを使用してここで文字列リストを変更できるため、コンパイラは、あなたが言及したタイプの安全性の問題(文字列のリストにintを挿入する)のために、以下のようなコードを許可しません

IEnumerableは、コレクションに対する単なるイテレータです。

static void Main(string[] args)
{
    IList<string> strings = new List<string> { "a", "b", "c" };
    IList<object> objects = strings;  ** // This will give an error because compiler does not want you to do the line below **
    objects.Add(5);  // Type safety violated for IList<string> hence not allowed


    // The code below works fine as you cannot modify the strings collection using IEnumerable of object
    //IEnumerable<string> strings = new List<string> { "a", "b", "c" };
    //IEnumerable<object> objects = strings;
}

お役に立てれば。

于 2012-05-07T09:19:53.817 に答える
0

ではない要素が含まれている可能性があるため、に割り当てることはできIEnumerable<Parent>ませIEnumerable<Child> Child

しかし、IEnumerableを挿入として使用したい場合はどうなりますか?何かのようなもの :

IEnumerable<object> objects = ...;
IEnumerable<string> strings = objects

コンパイル時IEnumerable<object>に、に非が含まれていないことを知る方法はありませんstring。ただし、あなた(プログラマー)がそこにstringsしかないことを知っている場合は、実行時にキャストを行うことができます。

IEnumerable<string> strings = objects.Cast<string>();

ちなみに、タグの説明を確認することをお勧めします。

于 2012-05-07T12:18:07.353 に答える