2015-01-04 4 views
2

Итак, какие из следующих 2-х кодовых блоков «лучше» в отношении производительности/наилучшей практики и т.д.Лучшая практика для нескольких использований .Count

Назвав .Count собственности несколько раз при каждом использовании.

List<string> myStrings = new List<string>(); 
myStrings.Add("foo"); 
myStrings.Add("bar"); 

if (myStrings.Count >= 1) 
{ 
    Console.WriteLine(myStrings.Count); 
} 

Хранение счета один раз и его повторное использование, так как мы можем предположить, что никаких изменений в списке не будет.

List<string> myStrings = new List<string>(); 
myStrings.Add("foo"); 
myStrings.Add("bar"); 

int myCount = myStrings.Count; 
if (myCount >= 1) 
{ 
    Console.WriteLine(myCount); 
} 
+3

Не будет никакой разницы. JIT все равно оптимизирует его. – MarcinJuraszek

+0

В этом случае оптимизатор может доказать, что 'myStrings' не будет использоваться в другом потоке, но действительно ли это делает эту оптимизацию? – zmbq

+0

ИМХО, трудно сказать без контекста. Имеет ли несколько инструкций CPU значение производительности вашего приложения? Вы собираетесь обобщать вопрос/ответ для однопоточных и многопоточных приложений (т. Е. Где «List.Count» может меняться между двумя вызовами)? Производительность является субъективной и наилучшей практикой. Лучшая практика заключается в том, чтобы понять и реализовать то, что дает правильную семантику для ** вашего сценария **. Любые другие слепые советы * могут быть рецептом неприятностей в некоторых случаях. Пример. Http://stackoverflow.com/questions/27770138/tostring-and-string-concatenation-unexpected-behavior –

ответ

3

Для List<T> это не имеет особого значения, так как список хранит его количество и может его дешево вернуть.

Для метода расширения Count на произвольном IEnumerable вам следует использовать временную переменную, чтобы избежать многократного вызова Count. Это связано с тем, что метод расширения Count должен пройти всю коллекцию (он обнаружит IList и использует быстрый счетчик, но, например, yield return перечисления не реализуют IList).

+0

Очень хороший ответ, спасибо.Поэтому вы рекомендуете использовать второй метод для IEnumerable, но первый для списка? – Adrian773

+0

@ Adrian773: безопаснее использовать временную переменную в обоих случаях. Исключение составляет для 'Length' массива ... там вы должны использовать' Length' в выражении управления циклом, а не локальную переменную, которая содержит одно и то же значение, потому что JIT-компилятор зависит от доступа к 'Length 'для проверки границ в цикле. –

2

myStrings.Count фактически не рассчитывать ничего, он просто берет сохраненный счетчик и возвращает его. Таким образом, это будет более или менее одинаковым.

Замечания об идентичности, поскольку оптимизатор будет оптимизировать его, может быть правдой для такого простого случая, но определенно не будет правдой, если компилятор не может быть уверен, что список не доступен из другого потока.

+0

Я достаточно уверен, что среда выполнения имеет право оптимизировать вызов, даже если он не может доказать, что другой поток не получит к нему доступа. В конце концов, именно поэтому у нас есть блокировки, энергозависимые и т. Д. - чтобы сообщить время выполнения, что можно оптимизировать и что должно ждать синхронизации. – Stilgar

+0

Просто уточнить, «более или менее то же самое! =« Идентично »? Когда вы упоминаете оптимизацию, понимаете ли вы, что« оптимизатор »просто повторно использует результат, полученный от первого вызова? Очень хочется узнайте, правильно ли @Stilgar, так и кто-то еще хочет весить здесь? – Adrian773