ReSharper 2024.2 ヘルプ

コード検査: 複数列挙の可能性

次のコードスニペットを考えてみましょう。

IEnumerable<string> names = GetNames(); foreach (var name in names) Console.WriteLine("Found " + name); var allNames = new StringBuilder(); foreach (var name in names) allNames.Append(name + " ");

GetNames()IEnumerable<string> を返すと仮定すると、2 つの foreach ステートメントでこのコレクションを 2 回列挙することで、実際に余分な作業をしています。

GetNames() がデータベースクエリを生成すると、さらに悪化する可能性があります。その場合、2 つの呼び出し間でデータベースを変更するプロセスがあれば、両方の foreach ループで異なる値が得られる可能性があります。

この種の問題は簡単に修正できます。たとえば、シーケンスを配列またはリストに変換することにより、変数の初期化の時点で列挙を強制します。

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

残りのコードは、配列型とリスト型の両方が IEnumerable インターフェースを実装しているため、同じままにすることができます。

偽陽性

場合によっては、このインスペクションは、IEnumerable オブジェクトが列挙される前にいくつかのメソッドに渡された場合に誤検出を引き起こすことがあります。例:

public void Foo(IEnumerable<string> values) { ThrowIfNull(values, nameof(values)); var x = values.ToList(); // Possible multiple enumeration of IEnumerable } public static void ThrowIfNull<T>(T value, string name) where T : class { // custom check for null but no enumeration }

この場合、ReSharper は、メソッドが追加の列挙を行うことを前提としています。これはほとんどの場合に当てはまります。メソッドが実際に IEnumerable オブジェクトを列挙しない場合は、偽陽性を防ぐために、対応するパラメーターに [NoEnumerationAttribute] をマークすることができます。

public void Foo(IEnumerable<string> values) { ThrowIfNull(values, nameof(values)); var x = values.ToList(); // No warnings about multiple enumeration } public static void ThrowIfNull<T>([NoEnumeration] T value, string name) where T : class { // custom check for null but no enumeration }