1. C# / Говнокод #13426

    +129

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    public class DataLayer
    {
    ...
    public List<Employee> GetEmployees() { ... }
    public List<Department> GetDepartments() {...}
    public List<Roles> GetRoles() {...}
    }

    Обратил внимание, что некоторые коллеги любят использовать в качестве возвращаемых типов не обычные массивы, а обязательно List<T>.
    Долго гадал, что-ж такая за практика интерсная, на стеке прям несколько вопросов подрял.
    Затем, обратил внимание, что все они используют в качестве основного инструмента паттерн MVC.
    Проштудировав самые известные книжки по MVC, таки нашёл виновника:
    http://www.ozon.ru/context/detail/id/19064535/ - Программирование на основе Microsoft ASP.NET MVC (Дино Эспозито)
    Везде где только можно, всё просто обделано LIst'ами. Даже данные передаваемые во View...

    Запостил: TauSigma, 15 Июля 2013

    Комментарии (134) RSS

    • в шарпе массив реализует Iterable?
      Ответить
      • Ага. Если я правильно понял явовский эквивалент.
        Ответить
    • Вы говорите так, как будто это плохо
      А вообще - я тоже всегда List<T> использовал. Почему не помню, но явно не из-за этой книжки. Возможно потому, что все остальные в конторе делали так же ;)
      Ответить
      • Вы говорите так, как будто это плохо
        А что хорошего-то? Есть динамические массивы, есть статические массивы.
        С чего вдруг такая нездоровая любовь к обёртке статических массивов?
        Ответить
        • С того, что T[] без конвертации никуда не запихнуть, многие вещи требуют энумератора.
          Ответить
          • >что T[] без конвертации никуда не запихнуть, многие вещи требуют энумератора.
            Ага. А как же.
            http://msdn.microsoft.com/en-us/library/9b9dty7d(v=vs.80).aspx
            Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable, you can use foreach iteration on all arrays in C#.
            Ответить
            • Хм. Склероз, однако ) Давно это было )
              Ответить
              • Да просто autocomplete их вроде не показывает.
                http://msdn.microsoft.com/en-us/library/system.array.aspx
                Starting with the .NET Framework 2.0, the Array class implements the System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T >, and System.Collections.Generic.IEnumerable<T > generic interfaces. The implementations are provided to arrays at run time, and therefore are not visible to the documentation build tools. As a result, the generic interfaces do not appear in the declaration syntax for the Array class, and there are no reference topics for interface members that are accessible only by casting an array to the generic interface type (explicit interface implementations). The key thing to be aware of when you cast an array to one of these interfaces is that members which add, insert, or remove elements throw NotSupportedException.
                Потому без каста не получается.
                В жабе кстати тоже костыльно массивы сделаны. Там так вообще нельзя.
                Ответить
    • А что, собственно, не так с List<T>?
      Ответить
      • Всё так, только не по назначению используется.
        Если массив будет в 100% использоваться для перечисления, то зачем его пихать в List<T>
        (Который в итоге всё равно вызовет newarr, да ещё и Array.Resize может вызвать при не умелом использовании.)
        Ответить
    • в чем говно-то?
      быть может в некоторых случаях List<T> медленнее, чем массив, но я посмотрю, как вы одной строчкой добавите новый элемент не переопределяя массив =)
      Ответить
      • В итоге:
        immutable vs mutable
        Ответить
        • TauSigma неправ, функционал List<T> и T[] сильно отличается, и в конечном итоге T[] всё равно прилодится конвертировать в List<T>
          Ответить
          • Прав. Отчасти.
            > функционал List<T> и T[] сильно отличается
            Без ололо-LINQ это было бы так. Но поскольку extension-методы добавляют практически всю функциональность листов, то...
            Ответить
            • Без ололо-линкью есть констроктор List<T>(T[]), но сути не меняет - не хочется ололо.
              Ответить
              • Есть конструктор List<T>(IEnumerable<T>)
                Ответить
                • Один хрен в Array всё скопируется:
                  public List(IEnumerable<T> collection)
                  {
                  	if (collection == null)
                  		ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
                  	ICollection<T> collection2 = collection as ICollection<T>;
                  	if (collection2 != null)
                  	{
                  		int count = collection2.Count;
                  		this._items = new T[count];
                  		collection2.CopyTo(this._items, 0);
                  		this._size = count;
                  		return;
                  	}
                  	this._size = 0;
                  	this._items = new T[List<T>._defaultCapacity];// Если массив больше 4х элементов (private const int _defaultCapacity = 4;), то будет вызываться Array.Copy...
                  	using (IEnumerator<T> enumerator = collection.GetEnumerator())
                  		while (enumerator.MoveNext())
                  			this.Add(enumerator.Current);
                  }
                  Ответить
                  • А что ещё можно сделать с IEnumerable?
                    Ответить
                    • Согласен, больше чем может сделать внутреннее хранилище List'а сделать не получится.
                      LINQ'вский ToArray() тоже оригинальностью не отличается:
                      internal Buffer(IEnumerable<TElement> source)
                      {
                      	TElement[] array = null;
                      	int num = 0;
                      	ICollection<TElement> collection = source as ICollection<TElement>;
                      	if (collection != null)
                      	{
                      		num = collection.Count;
                      		if (num > 0)
                      		{
                      			array = new TElement[num];
                      			collection.CopyTo(array, 0);
                      		}
                      	}
                      	else
                      	{
                      		foreach (TElement current in source)
                      		{
                      			if (array == null)
                      				array = new TElement[4];
                      			else
                      			{
                      				if (array.Length == num)
                      				{
                      					TElement[] array2 = new TElement[checked(num * 2)];
                      					Array.Copy(array, 0, array2, 0, num);
                      					array = array2;
                      				}
                      			}
                      			array[num] = current;
                      			num++;
                      		}
                      	}
                      	this.items = array;
                      	this.count = num;
                      }
                      Ответить
          • Говорите отличаются? Это рефлексия свойства Capacity класса List<T>:
            public Int32 Capacity
            {
            	get { return this._items.Length; }
            	set
            	{
            		if (value < this._size)
            			ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
            		if (value != this._items.Length)
            		{
            			if (value > 0)
            			{
            				T[] array = new T[value];
            				if (this._size > 0)
            					Array.Copy(this._items, 0, array, 0, this._size);
            				this._items = array;
            				return;
            			}
            			this._items = List<T>._emptyArray;
            		}
            	}
            }
            Ответить
            • По-моему, вы как раз только что показали, что да, отличается.
              Ответить
              • Естественно отличаются, List<T> расширяет интерфейс IList<T> на массив.
                Но если нужен Array, а не List, то надо использовать Array. Многие этой разницы не понимают.
                Ответить
                • Уточните, вы имеете ввиду T[] или класс Array? Если класс, то его вообще в топку - он не типизирован.
                  Ответить
                  • Вы будете удивлены:
                    System.Diagnostics.Debug.Assert(new Int32[] { }.GetType().BaseType == typeof(System.Array));

                    В IL'е это newarr, ldlen и stelem.ref.
                    Ответить
                    • Мне глубоко пофиг, что там в IL, я касты писать не хочу - мне лень писать лишнее ;)
                      Ответить
                • И, кстати, T[] не менее мутабелен, чем List<T>. Вся разница только в том, что у T[] вы не сможете изменить количество элементов.
                  Может быть такая проблема и есть, но явно не под тем углом, под которым вы её подняли.
                  Ответить
                  • Я про это и говорю, что используется не по назначению.
                    Если взять за пример паттерн MVC, то передавать во View List<T> бессмысленно, т.к. данные уже должны быть подготовлены заранее, прежде чем отдавать их во View.
                    Дино Эспозито, когда писал свой "креатив" (а "креатива" там достаточно), этим правилом принебрёг, из этого и пошло поколение разработчиков, использущее везде где только можно List<T> без разбора.
                    Ответить
          • List<T> содержит в себе T[].
            Так или иначе работаем с массивом.
            Ответить
        • С каких пор массивы Immutable?
          Ответить
      • быть может в некоторых случаях List<T> медленнее, чем массив
        Внутри List<T>'а обычный массив. И если ему не хватает места вызывается Array.Resize(...).
        Он не может быть быстрее себя самого с обёрткой.

        как вы одной строчкой добавите новый элемент не переопределяя массив
        Я не спорю, если массив динамический.
        Но если это уже готовые данные, которые никуда ресайзить не надо, то зачем его List<T>'ом отдавать.
        Это так и на остальные типы забить можно. Всё с лихвой в String влезет. Ещё и манипулировать можно как угодно.
        Ответить
        • Ну в жабе так тоже постоянно все делают.
          Когда-то давно, когда я только устроился на работу и начал писать такие же методы с массивами тимлид мне вообще прямо сказал - забудь про массивы - только листы, только хардкор. В те времена как раз вышла 5-я жаба и с женериками массивы потеряли свое последнее преимущество над листами.
          Я тогда его не понял, сейчас понимаю отчасти.

          Просто это как привычка. Лист - хорошая штука, это ж интерфейс по сути, а там может быть что угодно - Linked или массив. Обертка - хер с ним, мы ведь итак пишем на языках со сборкой мусора и кучей оверхеда.
          С массивами (в жабе) есть пара багов (нерабочие equals и hashCode) из-за которых нубам проще так и говорить - юзай лист и не думай.

          Считайте это энтерпрайзом головного мозга или просто желанием сделать код универсальнее.
          Ответить
          • >С массивами (в жабе) есть пара багов (нерабочие equals и hashCode)
            Как hashCode может работать в изменяемом обьекте? А откуда там equals?

            Почему-то мне ЭГМ это не кажется.
            Ответить
            • >Как hashCode может работать в изменяемом обьекте? А откуда там equals?
              Как говаривал мне когда-то один 80-летний дедушка: ум человека можно оценить по тем вопросам которые он задает.
              После чего я стал думать перед тем как у него что-то спрашивать.
              Ответить
              • Плюсую твоего дедушку. Вот я иногда глупости спрашиваю из-за того, что в гугл лень сходить. Так что если бы твой дедушка был ещё жив сейчас, то он бы говаривал: Ленивость человека можно оценить по тем вопросам которые он задает.
                Ответить
              • Не столько ум, сколько (не)желание учиться. Хочешь спязднуть что-то псевдоюморное - заткни варежку и пездуй дальше.
                Ответить
                • >Не столько ум, сколько (не)желание учиться
                  Не льсти себе.
                  Ответить
                  • Я не льщу. Пытаешься сойти за умного -> не задаешь "глупых" вопросов -> не учишься, вместо этого отвечаешь на чужие вопросы -> помогаешь другим учиться. Вот на что ты меня пытаешься подписать. Иди-ка ты нахуй.
                    Ответить
                    • >>Пытаешься немного включать голову -> не задаешь "глупых" вопросов
                      Даже не умеешь читать что пишут другие люди.
                      Тебе не помогут ответы других людей, поскольку ты не сумеешь их понять.
                      Ответить
                      • Смотря что они пишут. Высеры Царя я не понимаю, но и не очень-то хочется, впрочем, ему это на лоре уже сказали.
                        Ответить
                        • Поэтому ты питух, те, кто пытается что-то понять - понимают царя. Ты не пытаешься понять - ты не понимаешь царя, ты понимаешь лишь тех, кто не пытается понять.
                          Ответить
                          • Звучит, словно коан.
                            Ответить
                          • ...и пришел Царь, и произнес Слово. И было это Слово тайной непостижимой. Каждый, кто познал Слово становился подобен Царю. Но труден путь познания Слова, ибо способен смертный понять лишь тех, кто не пытался постичь Слово....
                            Ответить
                            • ...и было Слово 32-битным, ибо все остальное для питухов.
                              Ответить
                              • 64-битным же.
                                Ответить
                                • Царь разве под 64 бита пишет?

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

                                    Я вставлял слово - 32битная питушня, 386/486-е говно. Стек говно, во всех моих портянках 64битные инты - и да, я за 32бита - круто.
                                    Ответить
                                  • Тут своих плюсуют. Ты пока не свой в доску. Пока твой вес в нашей организации слишком мал. Если съешь с нами пуд соли, тогда и тебя начнут. Плюсуют только тех кто много съел и стал жирным весомым элементом нашего общества троллей
                                    Ответить
                                    • Это был ответ на вопрос anonimb84a2f6fd141 :
                                      > Пц, почему борманда плюсуют за мой комент? Ничиво нипанимаю, тут своих плюсуют?
                                      Ответить
                                    • > Тут своих плюсуют.
                                      Да не. Просто его утверждения противоречат словам царя, а мое про 64 бита - нет.
                                      Ответить
                            • Трудно найти смысл в словах Царя. Особенно, если его там нет.
                              Ответить
                              • Это слив-питушок из треда про гигобайт на гигагерц? Слился там - пришел сюда кукарекать?
                                Ответить
                                • Да нет, просто мне надоело вести разговор в таком тоне. Я не для того трачу своё личное время на заполнение пробелов в твоих знаниях точных и естественных наук, пытаясь сохранять доброжелательность, чтобы в ответ получать поток бессвязных и необоснованных оскорблений. Был бы ты повоспитаннее — ещё бы поговорили.
                                  Ответить
                                  • Очень тонко - записать собеседнику слив лишь потому, что он не стал отвечать, хотя на самом деле он всего лишь решил, что тут попросту не на что отвечать.
                                    Ответить
                                    • http://lurkmore.to/Правила_демагога, пп. 19, 46, 47
                                      Ответить
        • Плюс (в жабе) у листов есть куча полезных методов, которых массивы лишены:
          indexOf(), containsAll(), iterator() и проч.
          Ответить
    • Не вижу ГК, разве что жабистам будет немедленно резать глаз то, что используется List (класс), а не IList (интерфейс). В Жабе практика использовать в API именно интерфейсы коллекций стандартна и нормальна.
      Ответить
      • > жабистам будет немедленно резать глаз то, что используется List (класс), а не IList (интерфейс)
        Какой еще IList?
        Ответить
        • Приехали...

          http://msdn.microsoft.com/en-us/library/5y536ey6.aspx
          Ответить
          • http://docs.oracle.com/javase/6/docs/api/java/util/List.html
            Как раз джавистам глаз ничего резать не будет.
            Кстати в прошлом году гугол выдавал сцылки на документацию JDK4, может с выходом 8-ой наконец-то появится JDK7?
            Ответить
            • Джавистам будет резать глаз использование интерфейса вместо класса.

              То, что в .NET IList соответствует List, а List - ArrayList, сути дела не меняет.
              Ответить
        • abstract interface IList
          Ответить
    • List гораздо более гибок, чем массив, т.к. может иметь любую реализацию, хоть иммутабельную
      и при изменениях потребуется гораздо меньше сил на рефакторинг
      Ответить
      • И как, часто пиходится делать такой рефакторинг, где приходится в GUI или REST сервисе использовать возможности List'а?
        Ответить
        • т.к. он и используется, то - нет )
          Ответить
          • По мне, так не хорошая картина получается, так и Int64 вместо SByte'а можно использовать, да и про плюсовые TRUE/FALSE говорить не буду, они тоже гораздо гибче Boolean'а в .NET'е.

            А пример есть, где такой реальный рефакторинг был, что пришлось потратить много сил переделывая из newarr в List?
            Ответить
            • да, но не в шарпе, а в жабе
              Ответить
              • Лизавших жабу у нас нет.
                Несколько коллег пытались полизать, но жаба оказывалась достаточно шустрой и ускользала. ;)
                Ответить
        • add, addAll, indexOf, subList - сплошь и рядом.

          Плюс в Guava есть куча плюшек вроде ImmutableList, Iterables.concat, Iterables.filter, Lists.partition и много ещё чего, что на массивах не работает.
          Ответить
    • Очень даже поддерживаю TauSigma. Но лучше не обычный массив использовать а только IEnumerable.
      Благодаря ему можно будет через слои передавать не сам объект а ссылку на него и только в том месте где нам понадобятся данные, сохранить в память, то есть сделать ToList();
      Ответить
      • > через слои передавать не сам объект а ссылку на него
        Не понял

        > не обычный массив использовать а только IEnumerable
        Элегантно придавая всем операциям сложность O(N)
        Ответить
        • Ilist наверное все-таки удобнее будет, чем IEnumerable.
          Ответить
          • Почему IList, а не ICollecion?
            Ответить
            • Я просто не знаю, какие интерфейсы есть для шарпоколлекций :) Ляпнул первый не IEnumerable, который пришел в голову.

              А что ICollection умеет по сравнению с IEnumerable?
              Ответить
              • Это я тоже ляпнул не подумав, ICollection - базовый интерфейс динамических массивов.
                Add(...), Remove(...), Count

                Если не получается IEnumerable, то лучше обычный, базовый, массив T[] (Array).
                Ответить
        • Не верно выразился.
          Передавай Ienumerable, что бы потом создать из него list.

          >Элегантно придавая всем операциям сложность O(N)
          Нет, вот операции проделывать с list, который мы получим из Ienumerable.
          Ответить
          • > > Элегантно придавая всем операциям сложность O(N)
            > Нет, вот операции проделывать с list, который мы получим из Ienumerable.

            Превращение IEnumerable -> List уже O(N). Если бывает необходимость такой конверсии, почему же сразу не возвращать список?..
            Ответить
            • А если вам будут нужны другие коллекции? Например в какой-то момент вам нужно получить Dictionary.
              Вам придется из листа создать новый объект, и он останется. И так всегда, когда вам нужно будет работать с другим типом коллекций. Тогда зачем его сразу превращать.
              Ответить
        • > IEnumerable
          > Элегантно придавая всем операциям сложность O(N)
          Если ты используешь IList<T>, то ты и так не знаешь какая сложность при этом получится. Если там за ширмой ArrayList<T> (aka List<T>), то вставка\удаление в середину O(n), в то время как индексирование O(1), а если LinkedList<T>, то ситуация совершенно обратная. Да и вообще зачем выделять целых 100500 элементов, если тебе понадобиться лишь первые 3 записи. Ситуация ещё хуже, если ты вернул List<T>, а результат нужен только для чтения, а ты ради производительности не сделал копию (что конечно же глупо, особенно в условиях существования ReadOnlyCollection<T>). Так что тут в любом случае рекомендация делать наиболее обобщенно, а именно IEnumerable<T>. Он и менять не позволяет. Он и лишних элементов не считает. Воспользуешься .Take(3), а там уж передашь в конструктор ArrayList<T> или LinkedList<T> в зависимости от того - какие операции тебе будут чаще нужны. На уровне DataLayer вопросы наиболее часто используемых операций в клиентском коде не решаются, поэтому только IEnumerable<T>, если можешь. Вот снизу подсказывают про файл. В Шарпике для закрытия энумерабельных файлов есть using. PS Борманду: Не то что в каком то там Хаскеле.
          Ответить
        • > не обычный массив использовать а только IEnumerable
          >Элегантно придавая всем операциям сложность O(N)
          Если не использовать обращение по индексу, то она и так будет O(N).
          Ответить
      • > не сам объект а ссылку на него
        А в шарпике же как и в жабе - все объекты и массивы и так передаются по ссылке. И только примитивы и структуры по значению..

        Или вы имеете в виду ленивость? Т.е. то, что список будет строиться только тогда, когда сделают ToList или побегут по енумерейблу. Ну это далекооо не всегда можно применить... Тот же курсор от базы или файл часто нужно закрыть почти сразу после запроса/чтения, а тогда никакой ленивости не получится - нужно читать все что нужно и закрывать.
        Ответить
        • Да, имел ввиду ленивость. Да тогда нужен будет List.
          Ответить
        • А ты не помнишь, что-за такой контейнер (в теории алгоритмов), в котором каким-то образом используется код грея (может быть для преобразования индекса i контейнер1[i])? Там может быть даже бинарное дерево использовалось.
          Ответить
    • Мне всё-таки достаточно странно видеть вместе такие вещи, как:
      1. Entity Framework, LINQ, ASP.NET MVC.
      2. Использование Array вместо List<T> в целях улучшения производительности.

      Как-то совсем уж странно. Что-то тут не так.
      Ответить
      • Я тут про призводительность ничего не говорил. Скорее использование не по назначению.
        К стати, провёл несколько тестов, код:
        http://govnokod.ru/13301
        получается быстрее копирования по свойствам через рефлексию, если массивы получаются больших размеров.
        Ответить
        • "Не по назначению" - расплывчатый термин. Когда база данных используется для хранения двух целых чисел - это не по назначению. Когда одну тривиальную реализацию IList<T> предлагают использовать вместо другой, тут нужны какие-то более веские основания. Пока нет оснований делать вывод о том, будут ли коллекции меняться, речь может идти только о производительности. Приведу две ссылки.

          http://govnokod.ru/13426#comment188414
          http://govnokod.ru/13426#comment188415

          Речь может идти исключительно о производительности, непосредственной или опосредованной.

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

          Что касается того поста. Понимаете, нет такого вопроса, что быстрее, клонирование сериализацией, клонирование через отражение или какой-то другой экзотический способ. Есть вопрос, что меньше нагрузит наш сервер. И есть факт: написание кода клонирования многократно быстрее любого другого способа клонирования. Когда нужно клонировать 500 объектов, каждый из которых в процессе клонирования сериализацией выдаёт поток в 50Кб, серьёзно нагружает систему и исполняется слишком долго, чтобы это можно было делать несколько раз в секунду, сам факт, что это работает быстрее отражения, ничего не значит. Если нужно, чтобы такая операция вообще никак не отражалась на состоянии сервера, нет никаких других вариантов.
          Ответить
          • Речь может идти исключительно о производительности, непосредственной или опосредованной.
            needle более правильно сформулировал мою мысль:
            http://govnokod.ru/13426#comment188515
            Приведите код, очень стало интересно. По каким причинам у Вас отражение + работа с потоком байт оказалось быстрее просто отражения. Здесь явно что-то не так.
            Да, я реально что-то напутал...
            http://ideone.com/XF1c2u
            Результат с прекомпилированном варианте (без mono) (+-2sec.):
            Serialize:
            Elapsed: 00.0025 s,  MemDelta:  121.39 KB,  GC count: 0
            
            Reflection:
            Elapsed: 00.0016 s,  MemDelta:   54.38 KB,  GC count: 0

            Measure с rsdn'а.
            Ответить
            • Эээ. Я туплю, или в этом коде реально замеряют время одного клонирования сраной структурки с тремя полями, и оно занимает 2.5мс (О_о)?
              Ответить
              • Будем надеяться, что такие нет.
                Ответить
                • Да, туплю, 100 структурок. 25мкс на клона. Что-то все равно многовато. Царю не понравится ;(
                  Ответить
                  • Т.е. сто стрктур по 24байта(если я правильно посчитал - это говно не читаемо). 240байт за 0.0025сек - это ((24×100)÷0.0025)÷(1024×1024×1024) = 0.00089407гигобайта в секунду. Да, круто. Что примерно в 10тысяч раз медленнее мемкопи - круто в памяти без кеша вообще. Если в кеше, то медленее в овер миллион раз.


                    Жава-жва, не смеши меня так.
                    Ответить
                  • Мне тоже это не нравится...
                    Но при этом, моя приверженность к RAD, сполна окупает негатив от такой производительности.
                    Ответить
                    • Возможно, Ваш коллега обладает своим взглядом на RAD. Ничего страшного. В RAD главное - быстро и достаточно адекватно решить задачу.
                      Ответить
                      • Оно меня ещё с .NET 1.1 удручает. Но тогда хоть о производительности кода думали более серьёзно т.к. язык достаточно высокого уровня, сейчас уже не то что не заморачиваются, а даже не думают о таких вещах как, скажем, парсинг Enum'а из строки.
                        Собственно, тенденция с List<T> просто очередной этап забивания.
                        Так что недалеки те дни, что код:
                        http://govnokod.ru/7004
                        Будет абсолютно нормальным.
                        Ответить
                        • Боюсь, тут дело не в языке, а в том наборе плюшек, которые он "предоставляет". Есть сборщик мусора, значит, о памяти не нужно думать вообще. Есть LINQ, значит, писать можно всё, что угодно. С++ не прощает легкомысленного подхода, поэтому уровень программистов С++ в среднем многократно выше.
                          Ответить
            • needle приводит странную логику, на мой взгляд.
              1. IEnumerable никак не поможет, если вдруг придётся изменить список на словарь. Использование IEnumerable может быть оправдано, но не ссылками на то, что вдруг может возникнуть необходимость что-то сделать с коллекцией.
              2. Использование таких вещей, как LINQ и Entity Framework, а также ninject и ASP.NET MVC не очень хорошо согласуются с рассуждениями о том, что некая коллекция из нескольких элементов при копировании фактически указателей будет обладать сложностью O(n). Это немного странно.
              Ответить
              • Давайте по другому вопрос поставим:
                У нас есть метод в BL, который отдаёт заранее определённый массив данных:
                public List<PreparedData> GetOrderedFilteredPagedEmployee(
                    UInt32 pageSize,
                    UInt32 pageNumber,
                    SortOrder order,
                    SortColumn column) { ... }

                Почему отдавть его в виде IEnumerable или T[] хуже, чем отдать его в виде List<T>?
                Зачем предугадывать поведение клиента и отдавать заранее подготовленный массив в виде List<T>?
                Ответить
                • Я не говорю, что IEnumerable или T[] хуже. Особенно, в конкретном примере. Но есть и встречный вопрос. Вот такой дизайн, он действительно предполагает серьёзные рассуждения о правильности реализации, об уместности List<T>, или всё-таки тут нет большого повода расстраиваться? Я, честно говоря, не вижу тут какого-то большого проекта на десятки человеко-лет. Люди поработали несколько месяцев, и забыли. Или я не прав?

                  Не понятно, где тут появляется Dictionary и возможность заменить List на Dictionary.
                  Ответить
                  • Или я не прав?
                    В примере
                    http://govnokod.ru/13426#comment188640
                    вы использовали List<T> не по назначению.
                    Понятное дело, можно свалить на "вот такой дизайн" и "написали и забыли". Но это был не более чем аналогичный тестовый пример.
                    Не понятно, где тут появляется Dictionary и возможность заменить List на Dictionary.
                    Если я правильно понял нашего коллегу, то Dictionary было взято в качестве примера Т.е.:
                    1) Чем проще базовый тип, тем проще с ним орудовать.
                    2) Гадать за клиента что за функционал ему понадобиться - бессмысленно.
                    Ответить
                    • Думаю, всё-таки я использовал List<T> по назначению, поскольку мне нужно было сериализовать именно List<T>. Я, конечно, мог бы сериализовать SortedList, как это было в исходном варианте, но List<T> мне показался вполне достойной альтернативой. Мне действительно понятен ход Ваших мыслей, но не понятно, где в исходном коде говно. Скорее, нюансы и предпочтения. Однако этот код, безусловно, является говном, если нарушает соглашения о кодировании, существенно отразился на понимании исходников или существенно навредил проекту. Я, к сожалению, не слишком привержен искусству ради искусства, и стараюсь смотреть в первую очередь на практическую сторону проблемы.
                      Ответить
                      • не понятно, где в исходном коде говно
                        List<T> будет работать значительно быстрее, если в конструктор List<T>, в строках 53 и 73, Вы сразу передадите capacity (_childCount). В таком случае не произойдёт копирования массива после 4го элемента (См. http://govnokod.ru/13426#comment188459)
                        Если пойти ещё дальше, то свойство Children инициализируется в 2х местах (53,73), хотя можно всю инициализацию осуществить в рекурсионном методе CreateChildren(...).
                        Ответить
                        • Я говорил про код из топика.

                          Мне известно о чудотворном свойстве конструктора, передающего капасити. Но в данном случае меня не интересует производительность кода, который создаёт тестовые данные. Во-первых, мы замеряет производительность не этого кода, во-вторых, этот код не имеет значения в данном примере. Ваш пример с массивом простейших данных показался мне неубедительным. Чаще всего нет нужды клонировать такой массив, но есть необходимость в клонировании дерева, которое очень часто состоит из множества объектов нескольких определённых типов.

                          Свойство Children инициализируется один раз для каждого объекта. В данном случае мне важна была простота написания лично для меня и понимания для других.

                          Словом, этот код мне ни разу не дорог, я нисколько не против того, если Вы напишете так, как считаете нужным.
                          Ответить
                          • Я говорил про код из топика.
                            Он там лишний. Функционал List'а во View никаким чудодейственым образом использоваться не будет и не должен.
                            Если, вдруг, он туда попал, то это прокол проектировщика Model'а.

                            Т.е. каждый объект должен использоваться к месту. Иначе и вправду близки те дни, что можно будет всё через String передавать...
                            Ответить
                            • Хорошо, пусть он будет лишним конкретно в коде Вашего проекта.

                              Мне, тем не менее, стало интересно, какие задачи Вам приходится решать. И не могли бы Вы оценить в любых удобных терминах и единицах измерения наиболее существенную проблему, которую Вам доводилось решать?
                              Ответить
                              • На прошлом месте я с интеграцией BizTalk'а не справился, хотя Certificate Authority подружить с клиентскими сертификатами на ключах Alladin'а удалось без проблем.
                                На текущем, недавно внедрил AppFabric на ферму серверов, т.к. они создавали приличную нагрузку на сервера данных при обновлении кешей. В будущем, как запустим очередную ветку развития бизнеса, планирую на одно решение внедрить CEP в виде StreamInsight.
                                До этого АСУ ТП занимался, но это уже больше к алгоритмам и к плюсам.

                                Вообщем, пока самый большой фейл с BizTalk'ом был... Надеюсь, на вопрос ответил.
                                Ответить
                                • Фейлы не очень интересны. Интересны успехи.
                                  Ответить
                                  • Вы не находите не справедливым, спрашивать меня вопросы, но при этом, не желаете сами отвечать на вопросы? ;)
                                    http://govnokod.ru/13426#comment188738
                                    Ответить
                                    • Я достаточно чётко и обстоятельно отвечаю на все Ваши вопросы. Однако, пользуясь Вашим же методом, должен сказать, что, если Вы для выражения вопросительной форме речи используете надежды и предположения, то это в корне некорректное их использование, как с точки зрения логики, так и в плане ситуационной корректности. Оборот "надеюсь, что..." не предполагает конструктивного продолжения беседы. Напротив, говорит о том, что у Вас сформировалось устойчивое не слишком позитивное мнение об обсуждаемом предмете. Да и сама форма предполагает, что беседа практически завершена. Если Вы зададитесь вопросом о том, почему Вы использовали именно такую форму речи, то ответ вряд ли будет вразумительнее ответа Вашего коллеги. Эта форма речи совершенно нелогична, если Вы хотите получить ответ на вопрос.
                                      Ответить
                                      • Вопрос (http://govnokod.ru/13426#comment188688):
                                        Какой гибкости?
                                        Не подразумевает по собой конструктивного общения?

                                        Перефразирую:
                                        Подскажите, пожалуйста, какую гибкость Вы подразумевали в своём примере использования List<T>, которую я упустил устроив такой рефакторинг?

                                        Если Вы зададитесь вопросом о том, почему Вы использовали именно такую форму речи, то ответ вряд ли будет вразумительнее ответа Вашего коллеги.
                                        А как бы Вы задали подобный вопрос, если-бы коллега всё отдавал List'ами без разбора?
                                        Ну и заодно, как-бы Вы на него ответили, если такой вопрос адресовали бы Вам?
                                        Ответить
                                        • Про гибкость. Конкретно в моём примере с клонированием сериализацией есть объект, который содержит 5 коллекций, 2 из которых по историческим причинам являются словарями. Эти коллекции нужны по веским причинам. Гибкость List<T> или словаря по сравнению с IEnumerable, думаю, достаточно очевидна.

                                          Как бы я задал вопрос? Я бы задал такой вопрос на проекте, в котором очень жёсткие требования ко всему. И скорее всего, зарезал бы на собеседовании. А когда проекты мелкие и длятся 2-4 месяца, по итогам эти проекты работают и всех всё удовлетворяет, я бы не стал уделять большого внимания таким мелочам. Я бы решил эти проблемы в течение испытательного срока такого программиста. Если они не решены у вас, то почему? - вот главный вопрос, который нужно задать.

                                          Есть фактор масштаба. Как правило, некультурный программист совершает более масштабные диверсии. Мне доводилось сокращать время процедуры с 65 часов до 54 минут, резко снижать требования к железу на сервере. Согласитесь, вот это - реальная проблема и подлинный говнокод. Соединения тред-статик - подлинный говнокод. Код, который невозможно читать - безусловно, тоже.

                                          У программиста может быть свой опыт, и он может вполне добросовестно делать не вполне правильные вещи. У программиста может быть задача на человеко-год, которую от него требуют выполнить в два раза быстрее. А сделать надо хорошо.

                                          Как бы ответил я. У меня всегда есть план работ и некая стратегия. Простой вопрос. Если есть иерархия на 120 классов на 6 уровнях, а всего под неё изменено 500 классов и создано 250 новых, и во всем этом возник мелкий технический долг, что перевешивает:
                                          а) наличие ценного и правильно написанного функционала, улучшившего параметры в 10 раз,
                                          б) или мелкая проблема, которую очень просто исправить?

                                          Технический же долг я оформляю в виде задач, которые выполняю, когда возникает возможность. Если мне указывают на мои явные ошибки, я их исправляю. А вообще я трепетно отношусь к тому, что называется производительность в мелочах.
                                          Ответить
                                          • Гибкость List<T> или словаря по сравнению с IEnumerable, думаю, достаточно очевидна.
                                            IEnumerable - база. В некоторых случаях, использование базы намного эффективней Array'я.
                                            1) Ленивая инициализация данных.
                                            Для примера:
                                            http://msdn.microsoft.com/en-us/library/system.resources.resourcereader.aspx
                                            Отдаёт уже инициализированный объект DictionaryEntry, если сборку, куда ссылается тип ресурса загрузить не удалось, то будет исключение. Но исключение будет только на тех ресурсах, сборку которых не удалось загрузить, а не на всём массиве целиком.
                                            2) Если из всего массива нужно будет всего n первых элементов. Или часть пропустить.
                                            3) Код читает данные из "опасного источника", который на следующем элементе может уйти в исключение. (Идентично пп.1, толко на этом остановка чтения.)
                                            4) У клиента есть возможность остановить входящий поток на полученных n элементах.

                                            Соовтетственно, отдавая базу, Вы делаете код не только более гибким в плане архитектуры, но ещё и даёте клиенту право распоряжаться полученными данными самостоятельно, а не думать как из объекта верхнего уровня, перевести данные в другой объект верхнего уровня.

                                            Я бы задал такой вопрос на проекте, в котором очень жёсткие требования ко всему.
                                            На моей практике, лучше держать всех соратников в тонусе, тогда тот, кто не уверен в использовании чего-то, лучше подойдёт и лишний раз спросит, чем сначала сделает такой "финт ушами", как с тред-статиком.
                                            Согласитесь, вот это - реальная проблема и подлинный говнокод.
                                            В большинстве своём, такой говнокод в рамки сайта не поместится.
                                            Если они не решены у вас, то почему?
                                            У нас много отделов.
                                            а) наличие ценного и правильно написанного функционала, улучшившего параметры в 10 раз,
                                            б) или мелкая проблема, которую очень просто исправить?

                                            Если а) подразумевает под собой "работает? - не трогай", то тогда лучше не трогать.
                                            Ответить
                                • Ну как, внедрил?
                                  Ответить
            • Всё это выглядит замечательно, пока структура не выглядит хотя бы вот так:

              [Serializable]
              public class DataItem
              {
              public Int32 Property1 { get; set; }
              public String Property2 { get; set; }
              public Int32 Property3 { get; set; }

              public DataItem Parent;
              public List<DataItem> Children;
              }

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

              http://ideone.com/Pplqja
              Ответить
              • Я и писал что такой вариант используется только для определённого случая:
                http://govnokod.ru/13301#comment185987

                Когда я изучал проблему с клонированием, то наткнулся ещё вот на такой вариант:
                http://whizzodev.blogspot.ru/2008/06/object-deep-cloning-using-il-in-c_20.html
                Но так и не дошли ручки его потестить.
                Ответить
                • Попробуйте реализовать ISerializable, Писать всё дерево объектов в BinaryWriter, а читать из BinaryReader. Сравните длину потока, скорость работы. А потом всё-таки сравните с простейшим клонированием. Там писать-то нечего, а разница будет заметная.

                  Более того, когда мы хотим скопировать поддерево, автоматизация без дополнительных сущностей никак не поможет. А такие моменты встречаются. Например, нам нужно отправить 50 байт, а приходится отправлять мегабайт. И так могут делать сотни клиентов. Нехорошо получается.
                  Ответить
                  • С клонированием проблема. Если вы заметили, то в
                    http://govnokod.ru/13301#comment185987
                    я писал, что объекты разные.
                    Один SourceData[] inArray, а второй OutputData[] outArray и клонировать один объект в другой объект - не выйдет...
                    У одного:
                    class SourceData { public String Property1 {get;set;} public String PropertyN {get;set;} }

                    у второго:
                    class OutputData { public String PropertyN {get;set;} public String Property2 {get;set;} }

                    Оба класса автогенерируемые, даже смысла нет заморачиваться и поддерживать ISerializable.
                    Например, нам нужно отправить 50 байт, а приходится отправлять мегабайт.
                    Я рад что хоть кто-то ещё переживает за траффик. А то тенденции с пиханием в тонкий клиент мегатонны jQuery и Ко., меня удручает...
                    Ответить
                    • Клонирование - это всё-таки создание объекта того же класса.
                      Ответить
                    • >А то тенденции с пиханием в тонкий клиент мегатонны jQuery и Ко., меня удручает...
                      На самом деле, с gzip и кешированием - всем похуй. Меня больше удручает долгая загрузка страницы, а если еще и синхронная подгрузка и скрипт не качается - страница виснет на это время.
                      Ответить
                      • Так, она и долгая из-за того, что весь хлам гузится на титульной странице без разбора.
                        На сайте сонистайл.ком, до взлома сети сони, в HTML вёрстке можно было историю изменения обнаружить с датами и авторами...
                        Ответить
              • Такой вариант избавит вас от необходимости использования List<T>'а:
                static DataItem[] CreateChildren(DataItem parent, int level = 0)
                {
                	DataItem[] result=new DataItem[_childCount];
                	for(int i = 0; i < _childCount; i++)
                	{
                		result[i] = new DataItem
                		{
                			Property1 = GetNextId(),
                			Property2 = GetNextId().ToString(),
                			Property3 = GetNextId(),
                			Parent = parent,
                		};
                
                		if(level < _levels)
                		{
                			result[i].Children = CreateChildren(result[i], level + 1);
                		}
                	}
                }
                Ответить
                • Насколько я понимаю, этот вариант избавляет меня также от необходимой мне гибкости
                  Ответить
                  • Какой гибкости?
                    Да, косяк там, т.к. писал прям тут. В конце не хватает: return result;
                    Ответить
                    • Да, хорошо, что я не компилятор, и понимаю, что есть метакод, и он может нести в себе некую идею вне зависимости от мелких неточностей.
                      Ответить
                      • Когда я спросил одного коллегу, который любит безразбору везде пихать List<T>, LINQ.ToList():
                        - Зачем тебе он везде?
                        Ответ меня очень удивил:
                        - А вдруг понадобится.
                        Надеюсь, в Вашем случае это не ответ.
                        Ответить
                        • Возможно, такой ответ был достоин вопроса.
                          Ответить
                • Переведи на меня.
                  Ответить
                  • Обзывайся на меня — переводишь на себя.

                    <?php
                    function CreateChildren($parent, $level = 0)
                    {
                    	$result=Array();
                    	for($i = 0; $i < $this->_childCount; $i++)
                    	{
                    		$result[$i] = Array
                    		(
                    			'Property1' => GetNextId(),
                    			'Property2' => strval(GetNextId()),
                    			'Property3' => GetNextId(),
                    			'Parent' => $parent
                    		);
                    
                    		if($level < $this->_levels)
                    		{
                    			$result[$i]['Children'] = $this->CreateChildren($result[$i], $level + 1);
                    		}
                    	}
                    }
                    Ответить
      • >>1. Entity Framework, LINQ, ASP.NET MVC.

        Очень крутая смесь технологий и при правильном построении архитектуры, можно быстро создать практически пол функционала приложения. Для этого можно еще добавить ninject и юнит-тесты.
        Ответить
        • Я говорил о совсем другом. Вы, пожалуйста, перечитайте.
          Ответить
          • А зачем по пунктам разбили? Тогда не нужно было разбивать предложение, смысл теряется.
            И да, я сначала получаю IEnumerable или ICollection, но в основном не из-за производительности, а для возможности создавать другие коллекции, которые реализуют этот интерфейс.
            Ответить
            • Разбил по пунктам, поскольку увидел несколько аспектов.
              Ответить

    Добавить комментарий