2017-02-10 1 views
1

Я понимаю, что IEnumerable может столкнуться с риском для возврата разных результатов при многократном запуске. Но это все еще проблема, если мы уверены, что базовый набор записей никогда не изменится между ними, и последовательность цикла не имеет значения вообще?Выполнение Перечислимое несколько раз, если источник данных остается неизменным

Сложно позвонить по телефону ToList/ToArray всюду без каких-либо соображений, что это всего лишь «возможный» риск. R # или VS могут просто отметить это как ошибку, если этого не должно было случиться.

Действительно ли это не исключение? Мы никогда не должны повторять IEnumerable несколько раз?

Это то, что на самом деле произошло. В однопоточной среде.

void Main() 
{ 
    var result = GetFile(new [] {path1, path2}) // hardcoded path 
} 

IList<SomeFile> GetFiles(IEnumerable<string> filePaths) 
{ 
    var paths = filePaths.ToArray(); // <-- why we have to do this ? 

    foreach(var path In paths) 
     // Throw exception if the path not exist. 
    foreach (var path In paths) 
     // Process and return a list of file 
} 

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

+0

_ "и последовательность цикла вообще не имеет значения" _ что это значит? В общем, может быть безопасно всегда перечислять его, если исходный источник не изменится, возможно, он даже будет желателен, но он всегда будет стоить. Если это просто переменная, кто-то может переусердствовать, что она еще не «материализовалась». Поместите запрос в метод, и вы не получите предупреждение resharper. –

+0

Можете ли вы привести конкретный пример того, что вы описываете? Иногда вызов '.ToList()' также несет в себе риск, если вы материализуете из более медленного источника данных большое количество записей, которые не понадобятся. – David

+0

Если ваш код не работает с индексаторами и вообще нет, тогда нет реальной причины при вызове 'ToList()' или 'ToArray()', поскольку в большинстве случаев это приведет к множественному перечислению 'IEnumerable'. Также стоит упомянуть, что эти методы создают * copy * базового перечисляемого, и если вам это не нужно, то это плохая идея. – Fabjan

ответ

0

Забота о получении другого результата на второй итерации является далекой секундой от гораздо более реалистичной проблемы с производительностью. Если ваш IEnumerable<T> на самом деле является коллекцией в памяти, вы рискуете воспроизвести его каждый раз, когда вы перечисляете. Это может быть очень дорогостоящим:

  • Если IEnumerable<T> приходит из другого выражения LINQ, вы проводите циклы процессора пересчитывать то же самое,
  • Если IEnumerable<T> приходит из базы данных, вы можете в конечном итоге повторного считывания данных из сервер,
  • Если IEnumerable<T> происходит из файла, вы будете перечитывать файл.

Ничто из перечисленного не влияет на правильность, но может значительно снизить скорость, особенно для больших наборов данных. Поскольку в наши дни память относительно дешевая, а система сбора мусора довольно надежна, временное сохранение коллекций в списке или массиве - недорогой способ избежать этой проблемы.

0

Если это встроенная память, а не абстрактно перечислимый объект - просто используйте соответствующий интерфейс (IReadOnlyCollection, IReadOnlyList и т. Д.) Вместо IEnumerable. Если вы используете IEnumerable, вы должны предположить, что он может быть любой IEnumerable реализация.

Смежные вопросы