29 января 2010

Существенно ли?

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

Т.е. "естественная" реализация:


  1. enum SomeEnum {...}
  2.  
  3. class BaseClass()
  4. {
  5.     public virtual IEnumerable<SomeEnum> GetValueSet()
  6.     {
  7.         return new SomeEnum[] { SomeEnum.Value1, SomeEnum.Value2 };
  8.     }
  9. }
* This source code was highlighted with Source Code Highlighter.

"Оптимизированная" реализация:


  1. enum SomeEnum {...}
  2.  
  3. class BaseClass()
  4. {
  5.     private static readonly SomeEnum[] valueSet1 = new[] { SomeEnum.Value1, SomeEnum.Value2 };
  6.     public virtual IEnumerable<SomeEnum> GetValueSet()
  7.     {
  8.         return valueSet1;
  9.     }
  10. }
  11.  
  12. class ChildClass() : BaseClass
  13. {
  14.     private static readonly SomeEnum[] valueSet2 = new[] { SomeEnum.Value3, SomeEnum.Value4 };
  15.     public override IEnumerable<SomeEnum> GetValueSet()
  16.     {
  17.         return valueSet2;
  18.     }
  19. }
* This source code was highlighted with Source Code Highlighter.

Или все-таки оптимизатора в данном случае следует считать параноиком, усилия которого .NET съест с большим аппетитом (равно как и GC съест возвращенные экземпляры массивов), и такие оптимизации как мертвому припарки?

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, а создание заведомо выкидываемых объектов в качестве синтаксического сахара (в этой и других подобных ситуациях) следует классифицировать как быдлокод?


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