Resharper: возможное многократное перечисление IEnumerable - PullRequest
37 голосов
/ 06 июля 2011

Я использую новую версию Resharper 6. В некоторых местах моего кода он выделил некоторый текст и предупредил меня о возможном множественном перечислении IEnumerable .

.

Я понимаю, что это значит, и при необходимости воспользовался советом, но в некоторых случаях я не уверен, что это действительно большое дело.

Как в следующем коде:

var properties = Context.ObjectStateManager.GetObjectStateEntry(this).GetModifiedProperties();
if (properties.Contains("Property1") || properties.Contains("Property2") || properties.Contains("Property3")) {
    ...
}

Он подчеркивает каждое упоминание properties во второй строке, предупреждая, что я перечисляю этот IEnumerable несколько раз.

Если я добавлю .ToList() в конец строки 1 (поворачивая properties с IEnumerable<string> на List<string>), предупреждения исчезнут.

Но, конечно, если я преобразую его в список, то он будет перечислять весь IEnumerable для создания списка в первую очередь, а затем перечислять список по мере необходимости, чтобы найти свойства (т.е. 1 полное перечисление и 3 частичных перечисления). Принимая во внимание, что в моем исходном коде это только 3 частичных перечисления.

Я не прав? Какой лучший метод здесь?

Ответы [ 2 ]

41 голосов
/ 06 июля 2011

Я не знаю точно, что на самом деле здесь находится properties, но если он, по сути, представляет нематериализованный запрос к базе данных, то ваш оператор if выполнит три запроса.

I suspect было бы лучше сделать:

string[] propertiesToFind = { "Property1", "Property2", "Property3" };
if (properties.Any(x => propertiesToFind.Contains(x))
{
     ...
}

Это будет логически только итерация по последовательности только один раз - и если есть запрос к базе данных, он вполне может простоиспользуйте предложение SQL «IN», чтобы сделать все это в базе данных одним запросом.

6 голосов
/ 06 июля 2011

Если вы вызовете Contains() для IEnumerable, он вызовет метод расширения, который будет просто перебирать элементы, чтобы найти его.IList имеет реальную реализацию для Contains(), которая, вероятно, более эффективна, чем обычная итерация значений (может иметь дерево поиска с хешами?), Поэтому она не предупреждает с помощью IList.

* 1006.* Поскольку метод расширения будет знать только, что это IEnumerable, он, вероятно, не может использовать какие-либо встроенные методы для Contains(), хотя теоретически было бы возможно идентифицировать известные типы и привести их соответствующим образом, чтобы использоватьих.
...