web-dev-qa-db-ja.com

「IEnumerableの可能な複数の列挙」を説明するResharperのサンプルコード

Resharperは次のことを警告することがあります。

IEnumerableの可能な複数の列挙

an SOこの問題の処理方法についての質問 があり、ReSharperサイトも物事を説明しています here 。代わりにこれを行う:

IEnumerable<string> names = GetNames().ToList();

私の質問は、この具体的な提案に関するものです。2つのfor-eachループでコレクションを2回列挙する結果になりませんか?

63
user2250250

GetNames()IEnumerableを返します。その結果を保存する場合:

_IEnumerable foo = GetNames();
_

その後、fooを列挙するたびに、GetNames()メソッドが再度呼び出されます(文字通りではなく、詳細を適切に説明するリンクは見つかりませんが、 IEnumerable.GetEnumerator() )。

Resharperはこれを見て、リストで具体化するなどして、ローカル変数にGetNames()を列挙するresultを保存することを提案します。

_IEnumerable fooEnumerated = GetNames().ToList();
_

これにより、fooEnumeratedを参照している限り、GetNames()の結果が1回だけ列挙されます。

これは重要です。たとえば、GetNames()が(遅い)データベース呼び出しを実行する場合など、通常は1回だけ列挙する必要があるためです。

materializedリストの結果であるため、fooEnumeratedを2回列挙することは問題ではありません。メモリ内のリストを2回繰り返します。

158
CodeCaster

これは、複数の列挙を理解するための最良かつ最も簡単な方法であることがわかりました。

C#LINQ:IEnumerableの可能な複数の列挙

https://helloacm.com/c-linq-possible-multiple-enumeration-of-ienumerable-resharper/

9
Ryan

GetNames()は2回呼び出されません。 IEnumerable.GetEnumerator()の実装は、foreachを使用してコレクションを列挙するたびに呼び出されます。 IEnumerable.GetEnumerator()内で何らかの高価な計算が行われる場合、これは考慮すべき理由かもしれません。

8
IronMan702

はい、間違いなく2回列挙します。しかし、ポイントは、GetNames()が計算に非常に高価な遅延linqクエリを返す場合、ToList()またはToArray()

4