IEnumerable <T>からICollection <T>に変換できません


94

私は以下を定義しました:

public ICollection<Item> Items { get; set; }

このコードを実行すると:

Items = _item.Get("001");

次のメッセージが表示されます。

Error   3   
Cannot implicitly convert type 
'System.Collections.Generic.IEnumerable<Storage.Models.Item>' to 
'System.Collections.Generic.ICollection<Storage.Models.Item>'. 
An explicit conversion exists (are you missing a cast?)

誰かが私が間違っていることを説明できますか?Enumerable、Collections、およびToList()の使用の違いについて非常に混乱しています。

追加情報

私のコードの後半には、次のものがあります。

for (var index = 0; index < Items.Count(); index++) 

アイテムをIEnumerableとして定義しても大丈夫ですか?


3
_itemのタイプとGet(string)のシグネチャ(具体的には戻り値の型)に関する詳細情報を提供できますか?
アンドリュー・バーネット博士

このようにタイプを変えてみませんか?public IEnumerable<Item> Items { get; set; }特別な理由はありICollectionますか?
シャドウウィザードは2012年

IEnumerable <T> Get(string pk);
サマンサJTスター

回答:


116

ICollection<T>IEnumerable<T>soから継承して、の結果を割り当てます

IEnumerable<T> Get(string pk)

ICollection<T>2つの方法があります。

// 1. You know that the referenced object implements `ICollection<T>`,
//    so you can use a cast
ICollection<T> c = (ICollection<T>)Get("pk");

// 2. The returned object can be any `IEnumerable<T>`, so you need to 
//    enumerate it and put it into something implementing `ICollection<T>`. 
//    The easiest is to use `ToList()`:
ICollection<T> c = Get("pk").ToList();

2番目のオプションはより柔軟性がありますが、パフォーマンスへの影響ははるかに大きくなります。別のオプションはIEnumerable<T>ICollection<T>インターフェースによって追加された追加機能が必要でない限り、結果をとして保存することです。

追加のパフォーマンスコメント

あなたが持っているループ

for (var index = 0; index < Items.Count(); index++)

で動作しますIEnumerable<T>が、非効率的です。を呼び出すたびに、すべての要素を完全に列挙するCount()必要があります。コレクションとプロパティ(括弧なし)を使用するか、foreachループに変換します。Count

foreach(var item in Items)

1
ICollectionによって追加された追加機能は何ですか?
サマンサJTスター

7
ICollection<T>は操作できますが(詳細はドキュメントを参照)、IEnumerable<T>列挙することしかできません。
アンダースアベル

さまざまなLINQクエリを実行できるものが必要です。リストにそのようなことを追加したり、実行したりする必要はありません。それは私がICollectionを使ったほうがいいという意味ですか?
サマンサJTスター

LINQは動作するIEnumerable<T>のでIEnumerable<T>、その場合は十分です。
アンダースアベル

31

からIEnumerable<T>に直接変換することはできませんICollection<T>。あなたはそれをに変換するためのToList方法を使用することができますIEnumerable<T>ICollection<T>

someICollection = SomeIEnumerable.ToList();


これは私にとってはうまくいきます。しかし、変換するのは良い考えですか、それともItemsの型としてIEnumerableを使用する方がよいでしょうか。IEnumerableを使用する場合、プログラムの後半で必要に応じてアイテムに対してより多くのアクションを実行できるように作成していますか?
サマンサJTスター

ICollectionはすでにIEnumerableを実装しています。利用可能なアクションについて懸念がある場合は、ICollectionを使用する必要があると思います。2つの実際の違いを読んでから、実際に何を使用するかを決定できれば、より良いでしょう
Haris Hasan 2012

ToList()を使用した場合にどのような利点があるかを理解しようとしています。データを取得したら、アイテムに対してLINQクエリを実行したいと思います。
サマンサJTスター

ToList()は機能しますが、コメントで述べたように、Get()はICollectionを返すため、実際にはICollection <T>にキャストするか、Get to ICollection <T>の戻り署名を変更する必要があります。 。/コピーToListメソッドを使用するか、てToArrayは動作しますが、それはまた、不要な作成のメモリがかかります操作
博士アンドリュー・バーネット・トンプソン

IEnumerableとICollectionの両方に対してLINQクエリを実行できます。利点..私が今知っているのは、Count ICollectionがカウントを維持し、IEnumerableがアイテムの数を計算して結果を返すことです。ICollectionは、Ienumerablesが提供しない追加のremoveメソッドを提供します
Haris Hasan

1

質問に関する詳細情報を保留中:

アイテムの種類とGetの署名に関する詳細情報を提供してください

試すことができる2つのことは次のとおりです。

  • _item.Get to(ICollection)の戻り値をキャストするには
  • 次に、_item.Get( "001")。ToArray()または_item.Get( "001")。ToList()を使用します。

2つ目は、アレイコピーのパフォーマンスが低下することに注意してください。Getの署名(戻り値の型)がICollectionでない場合、最初の署名は機能しません。IEnumerableでない場合、2番目の署名は機能しません。


質問とコメントであなたの説明に続いて、私は個人的に_item.Get( "001")の戻りタイプをICollectionに宣言します。これは、不要な作成/コピー操作を伴うキャストまたは変換(ToList / ToArrayを介して)を行う必要がないことを意味します。

// Leave this the same
public ICollection<Item> Items { get; set; }

// Change function signature here:
// As you mention Item uses the same underlying type, just return an ICollection<T>
public ICollection<Item> Get(string value); 

// Ideally here you want to call .Count on the collectoin, not .Count() on 
// IEnumerable, as this will result in a new Enumerator being created 
// per loop iteration
for (var index = 0; index < Items.Count(); index++) 

宜しくお願いします、


1
署名は次のとおりです。IEnumerable<T> Get(string pk); アイテムは、返されるアイテムレコードを保持するために使用されます。後で、これらを繰り返してレポートを作成します。うまくいくものなら何でも使っても大丈夫です。最適なデータ型は何だと思いますか?
サマンサJTスター

1
Getと一致するようにItemsのデータ型をIEnumerable <T>に変更するか、Itemsと一致するようにGet to ICollection <T>の戻り値の型を変更することをお勧めします。私はこれらの2つがちょうど異なって宣言された同じ基礎となるタイプであると思いますか?それらがToList()またはToArray()の使用を避けたいのと同じタイプである場合は、不要なメモリ割り当てと配列コピーを実行します。それらが同じタイプでない場合は、何らかの変換を行う必要があります
AndrewBurnett-Thompson博士

後でアイテムを使用する場所を示すために、質問に追加しました。同じ基になる型を言うとき、あなたは正しいです。
サマンサJTスター

さて、Getの戻り値の型を変更するだけです。変換(遅いToList / ToArrayを介して)やキャストを行う必要がないためです。これがお役に立てば幸いです:)
AndrewBurnett-Thompson博士
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.