28 января 2010

".NET именно для этого" или быдлокод?

Как вы относитесь к такому коду?


  1. private EntitySet persons;
  2. public void SomeMethod()
  3. {
  4.     /// ...
  5.     persons.ToList().ForEach(person => person.Id = Guid.NewGuid());
  6.     /// ...
  7. }
* This source code was highlighted with Source Code Highlighter.

Оставим в стороне аргументацию за и против лямбда-функций. Основное нарекание, разумеется, вызывает метод ToList(), используемый только для того, чтобы получить доступ к вожделенному методу ForEach(), отсутствующему в EntitySet, дабы получить красивый и понятный, с точки зрения разработчика, код, умещающийся в одну строку.

Предложение заменить "вожделенный" ForEach() следующим образом, аргументированное тем, что не тратятся ресурсы на создание List'а (как память, так и процессорное время на конструкцию и последующую сборку мусора), опровергается как нецелесообразное.



  1. foreach(var person in persons)
  2.     person.Id = Guid.NewGuid();
* This source code was highlighted with Source Code Highlighter.

Аргументация (приблизительная): «.NET для того и создан, чтобы о таких вещах не задумываться. Я смотрел Reflector'ом исходники .NET'а, там о производительности мало задумываются. Нет смысла оптимизировать кусок кода со сложностью o(), когда есть столь же часто вызываемый кусок кода со сложностью O(). Поэтому, если данный кусок кода не является узким местом, то создать объект наподобие List() и тут же отправить его на съедение сборщику мусора - это нормально. И вообще, если нужно оптимизировать в таких мелочах, то нужно отказаться от ASP.NET, и писать на C++».

На мой, субъективный взгляд, сомнительной оптимизацией (но как ни крути, а все же оптимизацией) можно считать требование отказаться от лямбда-функций (вызов метода ForEach для коллекции из N элементов - N+1 вызовов функций, на которых тоже можно сэкономить процессорные команды). А вот отказ от создания мимолетного объекта можно считать оптимизацией существенной, независимо от сложности других участков кода. Другими словами, первый кусок кода является сам по себе плохо пахнущим, и от таких необходимо избавляться.

Допустимым можно считать создание недостающего екстеншн-метода для повторного использования (при непреодолимой любви к лямбда-функциям):



  1. public static void ForEach(this IEnumerable array, Action action)
  2. {
  3.     foreach (var item in array)
  4.         action(item);
  5. }
  6.  
  7. public void SomeMethod()
  8. {
  9.     /// ...
  10.     persons.ForEach(person => person.Id = Guid.NewGuid());
  11.     /// ...
  12. }
* This source code was highlighted with Source Code Highlighter.

Непревзойденным (по соотношению наглядность/цена) по-прежнему остается "классический" foreach, а создание заведомо выкидываемых объектов в качестве синтаксического сахара (в этой и других подобных ситуациях) следует классифицировать как быдлокод?


И еще один подобный вопрос в продолжение.

1 комментарий:

Ilya Veselov комментирует...

Ну, в .NET 4.0 для параллельных операторов есть свой класс и выглядят они как Parallel.ForEach(); и ничего :)

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