Resharper: возможно многократное перечисление IEnumerable
Я использую новую версию 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 частичных перечисления.
Неужели я ошибаюсь? Какой лучший метод здесь?
Ответы
Ответ 1
Я точно не знаю, что ваш properties
на самом деле здесь, но если он по существу представляет запрос на немедленную базу данных, то ваш оператор if
выполнит три запроса.
Я подозреваю, что было бы лучше сделать:
string[] propertiesToFind = { "Property1", "Property2", "Property3" };
if (properties.Any(x => propertiesToFind.Contains(x))
{
...
}
Это будет логически только переходить по последовательности один раз - и если есть запрос к базе данных, он вполне может просто использовать предложение SQL "IN", чтобы сделать все это в базе данных в одном запросе.
Ответ 2
Если вы вызываете Contains()
в IEnumerable, он будет вызывать метод расширения, который будет просто перебирать элементы, чтобы найти его. IList
имеет реальную реализацию для Contains()
, которая, вероятно, более эффективна, чем регулярная итерация через значения (у нее может быть дерево поиска с хешами?), поэтому она не предупреждает с помощью IList
.
Поскольку метод расширения будет знать только, что он IEnumerable
, он, вероятно, не может использовать какие-либо встроенные методы для Contains()
, хотя в теории было бы возможно идентифицировать известные типы и соответственно их применять использовать их.