Вернувшись в более старые версии Delphi, которые не поддерживали записи с помощью методов, тогда использование object
было способом получить ваши объекты, выделенные в стеке. Очень редко это могло бы принести пользу производительности. В настоящее время record
лучше. Единственная функция, отсутствующая в record
, - это способность наследовать от другого record
.
Вы отказываетесь от многого, когда вы изменяетесь с class
на record
, поэтому учитывайте это только в том случае, если выгоды от производительности являются подавляющими.
Вторым путем Вы показали использованию дополнительный метод для выполнения метода делегата для каждого из элементов в списке.
Таким образом, у Вас есть другой делегат (=method) вызов.
Кроме того, существует возможность выполнить итерации списка с для цикл.
Одна вещь опасаться состоит в том, как выйти из Универсального.ForEach метода - см. это обсуждение . Хотя в ссылке, кажется, говорится, что этот путь самый быстрый. Не уверенный, почему - Вы думали бы, что они будут эквивалентны когда-то скомпилированные...
Между двумя существует одно важное, и полезное, различие.
, поскольку.ForEach использует for
цикл для итерации набора, это допустимо (редактирование: до .net 4.5 - измененная реализация и они оба бросок):
someList.ForEach(x => { if(x.RemoveMe) someList.Remove(x); });
, тогда как foreach
использование перечислитель, таким образом, это не допустимо:
foreach(var item in someList)
if(item.RemoveMe) someList.Remove(item);
<час> tl; доктор: НЕ Делайте copypaste этот код в Ваше приложение!
Этими примерами не является лучшая практика, они должны только продемонстрировать различия между ForEach()
и foreach
.
объекты Удаления из списка в for
цикл может иметь побочные эффекты. Наиболее распространенный описан в комментариях к этому вопросу.
Обычно, если бы Вы надеетесь удалять несколько объектов из списка, Вы хотели бы разделить определение который объекты удалить из фактического удаления. Это не сохраняет Ваш код компактным, но это гарантирует, что Вы не пропускаете объектов.
Список. ForEach () считается более функциональным.
List.ForEach()
говорит, что Вы хотите сделанный. foreach(item in list)
также говорит точно, как Вы хотите сделанный. Это уезжает List.ForEach
свободный изменить реализацию как часть в будущем. Например, гипотетическая будущая версия.Net могла бы всегда работать List.ForEach
параллельно под предположением, что в этой точке у всех есть много ядер CPU, которые обычно простаивают.
, С другой стороны, foreach (item in list)
дает Вам немного больше контроля циклом. Например, Вы знаете, что объекты будут выполнены с помощью итераций в некотором последовательном порядке, и Вы могли легко прервать середину, если объект удовлетворяет некоторому условию.
Я предполагаю эти someList.ForEach()
, вызов мог быть легко параллелизирован, тогда как нормальное foreach
не настолько легко идти параллельно. Вы могли легко выполнить несколько различных делегатов на различных ядрах, который не настолько легко сделать с нормальным foreach
.
Просто мои 2 цента
Негласно, в анонимного делегата превращаются фактический метод, таким образом, у Вас могли быть немного служебные со вторым выбором, если бы компилятор не принимал решение встроить функцию. Кроме того, любые локальные переменные, на которые ссылается тело анонимного примера делегата, изменились бы по своей природе из-за приемов компилятора для сокрытия того, что это компилируется в новый метод. Больше информации здесь о том, как C# делает это волшебство:
http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx
Я знаю две вещи неясного выхода, которые делают их отличающимися. Пойдите меня!
Во-первых, существует классическая ошибка создания делегата к каждому объекту в списке. Если Вы используете foreach ключевое слово, все Ваши делегаты могут закончить тем, что обратились к последнему объекту списка:
// A list of actions to execute later
List<Action> actions = new List<Action>();
// Numbers 0 to 9
List<int> numbers = Enumerable.Range(0, 10).ToList();
// Store an action that prints each number (WRONG!)
foreach (int number in numbers)
actions.Add(() => Console.WriteLine(number));
// Run the actions, we actually print 10 copies of "9"
foreach (Action action in actions)
action();
// So try again
actions.Clear();
// Store an action that prints each number (RIGHT!)
numbers.ForEach(number =>
actions.Add(() => Console.WriteLine(number)));
// Run the actions
foreach (Action action in actions)
action();
Список. Метод ForEach не имеет этой проблемы. Текущий объект повторения передается значением как аргумент внешней лямбде, и затем внутренняя лямбда правильно получает тот аргумент в своем собственном закрытии. Проблема решена.
(Печально я верю, ForEach является членом Списка, а не дополнительного метода, хотя легко определить его самостоятельно, таким образом, у Вас есть это средство на любом перечислимом типе.)
, Во-вторых, подход метода ForEach имеет ограничение. При реализации IEnumerable при помощи возврата урожая Вы не можете сделать возврата урожая в лямбде. Таким образом, цикличное выполнение через объекты в наборе для получения вещей возврата не возможно этим методом. Необходимо будет использовать foreach ключевое слово и работу вокруг проблемы закрытия путем ручного создания копии текущего значения цикла в цикле.
Для забавы я вытолкал Список в отражатель, и это - получающийся C#:
public void ForEach(Action<T> action)
{
if (action == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
action(this._items[i]);
}
}
Точно так же MoveNext в Перечислителе, который является тем, что используется foreach, является этим:
public bool MoveNext()
{
if (this.version != this.list._version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
if (this.index < this.list._size)
{
this.current = this.list._items[this.index];
this.index++;
return true;
}
this.index = this.list._size + 1;
this.current = default(T);
return false;
}
Список. ForEach намного более обрезается вниз, чем MoveNext - намного меньше обработки - будет более вероятный JIT во что-то эффективное..
, Кроме того, foreach () выделит новый Перечислитель несмотря ни на что., GC является Вашим другом, но если Вы сделаете тот же foreach неоднократно, это сделает больше холостых объектов, в противоположность многократному использованию того же делегата - , НО - это - действительно случай края. В типичном использовании Вы будете видеть минимальное различие.
OPENROWSET(BULK .....)
для загрузки файла из диска
– marc_s
30 May 2013 в 15:04
У нас был некоторый код здесь (в VS2005 и C#2.0), где предыдущие инженеры старались изо всех сил использовать list.ForEach( delegate(item) { foo;});
вместо foreach(item in list) {foo; };
для всего кода, который они записали. например, блок кода для чтения строк от dataReader.
я все еще не знаю точно, почему они сделали это.
недостатки list.ForEach()
:
Это является более подробным в C# 2.0. Однако в C# 3 вперед, можно использовать" =>
" синтаксис для создания некоторых приятно кратких выражений.
Это менее знакомо. Люди, которые должны поддержать этот код, зададутся вопросом, почему Вы сделали это тот путь. Это взяло меня некоторое время, чтобы решить, что не было никакой причины, кроме, возможно, чтобы заставить писателя казаться умным (качество остальной части кода подорвало это). Это было также менее читаемо, с" })
" в конце блока кода делегата.
См. также книгу Bill Wagner "Эффективный C#: 50 Особенных методов Улучшить Ваш C#", где он говорит о том, почему foreach предпочтен другим циклам как для или циклы с условием продолжения - основной момент, состоят в том, что Вы позволяете компилятору решить лучший способ создать цикл. Если будущей версии компилятора удастся использовать более быструю технику, то Вы получите это бесплатно при помощи foreach и восстановления, вместо того, чтобы изменить Ваш код.
foreach(item in list)
конструкция позволяет Вам использовать break
или continue
, если необходимо выйти из повторения или цикла. Но Вы не можете изменить список в цикле foreach.
я удивлен видеть, что list.ForEach
немного быстрее. Но это - вероятно, не допустимая причина использовать его повсюду, который был бы преждевременной оптимизацией. Если Ваше приложение использует базу данных или веб-сервис, который, не управление циклом, почти всегда будет, то, куда время проходит. И Вы сравнили его с for
цикл также? Эти list.ForEach
мог произойти быстрее из-за использования этого внутренне и for
, цикл без обертки будет еще быстрее.
я не соглашаюсь, что list.ForEach(delegate)
версия "более функциональна" любым значительным способом. Это действительно передает функцию функции, но нет никакой большой разницы в организации программы или результате.
я не думаю, что foreach(item in list)
, "говорит точно, как Вы хотите сделанный" - for(int 1 = 0; i < count; i++)
, цикл делает это, foreach
, цикл оставляет выбор управления до компилятора.
Мое чувство, на новом проекте, для использования foreach(item in list)
для большинства циклов для соблюдения общего использования и для удобочитаемости и использования list.Foreach()
только для коротких блоков, когда можно сделать что-то более изящно или сжато с 3 дюймами C# =>
" оператор. В случаях как этот может уже быть дополнительный метод LINQ, который более конкретен, чем [1 119]. Посмотрите, не делает ли Where()
, Select()
, Any()
, All()
, Max()
или один из многих других методов LINQ уже то, что Вы хотите от цикла.
Вы могли назвать анонимного делегата:-)
, И можно записать второе как:
someList.ForEach(s => s.ToUpper())
, Который я предпочитаю и сохраняю большой ввод.
, Поскольку Joachim говорит, параллелизм легче относиться к второй форме.