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

    +129

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    static string BuildPostData(IDictionary<string, string> d)
    {
            var s = "";
            for (var i = 0; i < d.Count; i++)
            {
                 var item = d.ElementAt(i);
                 var key = item.Key;
                 var val = item.Value;
    
                 s += String.Format("{0}={1}", key, HttpUtility.UrlEncode(val));
    
                 if (i != d.Count - 1)
                     s += "&";
            }
            return s;
    }

    Встретил вот такое.... переписал кодом ниже. Меньше мусора и работает намного быстрее.
    static string BuildPostData(IEnumerable<KeyValuePair<s tring, string>> d)
    {
    return string.Join("&", d.Select(i => string.Format(CultureProvider.Common, "{0}={1}", i.Key, HttpUtility.UrlEncode(i.Value))));
    }

    Запостил: indigo_projects, 19 Июня 2013

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

    • Что-то мне ваш код тоже не нравится.
      Ответить
      • А можно ваш вариант, не холивара ради, а для расширения кругозора.
        Ответить
        • Я не знаю тонкостей задачи, но мне кажется топикстартер тупо пользовался подсказками решарпера.
          Вот например, какую коллекцию кроме словаря aka dictionary<tkey, tvalue> они собираются получать на входе.
          Зачем там задана культура, вдь с латиницей же работают люди, для чего энкодинг мне тоже не очень понятно.
          Почему строку "&" не вынести в string.format, тогда можно было бы просто создать стрингбилдер и обойтись одним проходом по коллекции.
          Ответить
          • > для чего энкодинг
            Чтобы полученную строу параметров не распидорасило от val, в котором есть &, % или другие спецсимволы.

            > Почему строку "&" не вынести в string.format
            Потому, что после последнего параметра она не нужна.

            P.S. Неужели в шарпе изкоробки нет нормального построителя HTTP запросов, который соблюдает все правила составления урлов? Чего-нибудь в духе
            QueryString s = new QueryString();
            s.Add("param1", "value1");
            s.Add("param2", "value2");
            Ответить
            • >>Чтобы полученную строу параметров не распидорасило от val, в котором есть &, % или другие спецсимволы.
              Энкодинг только на валью, а не на всю строку.
              >>Потому, что после последнего параметра она не нужна.
              Это прогблема сделать ее в стрингформате до?

              Есть. WebClient, HttpRequest, HttpResponse, тысячи их.
              Ответить
              • Приведите пример, как с помощью этих классов закодировать строку параметров.
                Ответить
              • > Энкодинг только на валью, а не на всю строку.
                Так он и энкодит только value. Ну я бы еще key, конечно, заэнкодил. А вот всю строку целиком энкодить нельзя (я думаю вы понимаете, почему).

                > Это прогблема сделать ее в стрингформате до?
                А слева она нахера? Чтобы потом ее потом отрезать сабстрингом?
                Ответить
            • Странно, метод для разбора есть: HttpUtility.ParseQueryString а для составления вроде нету...
              Ответить
          • >> BuildPostData
            > Я не знаю тонкостей задачи

            По моему, всё вполне очевидно: нужно подготовить тело для POST-запроса.
            Ответить
            • Кстати с тем же успехом эта функция прокатит и для get запроса...
              Ответить
            • Ага, а параметры в урле передаются что ли?
              По коду сужу а не по названию метода.
              Ответить
              • Вы в курсе, как передаются параметры в POST-запросах?
                Ответить
                • Роман, а вы не огорчитесь, если я немного поупотребляю слова анскильность и питушня? Просто сегодня они как нельзя в тему.
                  Ответить
                  • Меня вообще сложно огорчить, так что валяйте. Кажется, эти слова уже стали мемами вроде джвух стеков и поясните мысль.
                    Ответить
                    • Да просто я не знаю, какие еще слова говорить, когда люди яростно отстаивают свою точку зрения, ничего не понимая в проблеме, и даже не представляя задачу.

                      Цитата: Ага, а параметры в урле передаются что ли?
                      Цитата: Это прогблема сделать ее в стрингформате до?
                      Цитата: для чего энкодинг

                      Ну ладно бы просто незнание, в незнании нет ничего страшного, всегда можно найти\спросить\додумать. Другое дело когда человек не знает, но считает, что он прав. Вот это и можно назвать анскильностью. А код с "&{0}={1}" - некорректной питушней.
                      Ответить
                      • Вот я додумаю и доспорю. Потому, что я так думаю, что код - говно.
                        А вы можете называть как хотите.
                        Ответить
                        • > Потому, что я так думаю, что код - говно.
                          Буду рад увидеть ваш вариант.

                          Ответить
                      • И гневных слов в свой адрес я тоже не заслужил.
                        Я просто ошибся, чуточку.
                        Ответить
                        • > И гневных слов в свой адрес я тоже не заслужил.
                          Гневные слова не за незнание, отнюдь, а только за стиль подачи этого незнания в духе "я все знаю, а вы все питушки" ;)
                          Ответить
                          • Я этого не говорил. Это вы так сами решили, видимо потому, что я с вами был не согласен.
                            Ответить
                            • Само собой не говорили. Если бы говорили - я бы писал более жестко ;) Просто тон некоторых фраз как бы намекает нам об этом:
                              Я не знаю тонкостей задачи, но мне кажется топикстартер тупо пользовался подсказками решарпера.
                              Это прогблема сделать ее в стрингформате до?
                              Ага, а параметры в урле передаются что ли?

                              Я ничего не имею против такого тона, когда говорящий им на 146% уверен в своей правоте. Да что тут далеко ходить, я сам так часто пишу ;) Но когда такой стиль речи юзают не зная темы - это не айс. В конце-концов, если не уверен, можно написать "емнип" или "имхо" или "мне кажется".

                              /thread
                              Ответить
                • Ну да. Но ее же в шарпе не строят вручную.
                  Хотя смотря какую.
                  Вот по этому хотелось бы задачку.
                  Ответить
                  • Задача - есть словарь, в котором лежат ключи/значения. Нужно построить строку, подходящую для GET или POST запросов. В GET'е она пойдет непосредственно в url, в post'е - в тело запроса. Если возможно - привести более адекватный вариант построения запроса, в котором эту строку строить не нужно вообще (может быть есть возможность передать в HttpRequest прямо словарь?).
                    Ответить
                  • > Вот по этому хотелось бы задачку.
                    Попробуйте программно запостить сюда http://validator.w3.org/check документ на валидацию.
                    Ответить
                    • А там разве запрос передается не методом get?
                      Отправил парочку, просмотрел тело, параметры в урле, метод - get.
                      Ответить
                      • Нужно выбирать validate by direct input: http://validator.w3.org/#validate_by_input
                        Моя первая ссыль - это url обработчика формы, на который приходит POST
                        <form method="post" enctype="multipart/form-data" action="check">
                        Ответить
          • neeedle, такое ощущение что Вы не совсем понимаете о чем пишете. надо собрать строку из элементов коллекции, с разделителем &. Именно для этого есть метод в string - Join, а то что при этом привожу элементы в нужный мне вид - решарпер вообще тут ни при чем. Чем обуславливается необходимость использовать StringBuilder и Вы тоже будете ловить ситуации когда добавлять & к строчке когда нет?
            Ответить
            • > Чем обуславливается необходимость использовать StringBuilder
              Той же самой причиной, по которой пыхеры пишут ' вместо ". Потому что так работает быстрее. И насрать им, что сам HTTP запрос исполняется на 3-4 порядка медленнее, чем его построение, и стринг билдер тут даст никому не нужный профит в жалкие наносекунды (зато явно снизит читабельность)...

              Основная причина такого рода оптимизаций - анскильность (простите за слово из лексикона Царя, но оно мне понравилось), и незнание того, что оптимизировать нужно "горячий" код, а не все подряд.
              Ответить
              • А зачем два linq метода, если можно обойтись одним?
                Ответить
                • А зачем писать велосипед клеящий строки вручную, если Join всяко реализован оптимальным образом?

                  > одним
                  Код в студию.
                  Ответить
                  • Я подумаю и сделаю так, как бы сделал я.
                    А не исходя из ГК.
                    Ответить
                    • Ок, я выше описал задачу. Давайте решать ;)
                      Ответить
                • не понял почему два linq запроса?
                  Ответить
                  • join тоже к linq относится.
                    Ответить
                    • http://msdn.microsoft.com/ru-ru/library/system.string.join.aspx
                      Как именно? Потому что может принимать IEnumerable?
                      Ответить
                      • нет, я определяю по отношению к неймспейсу.
                        Но блин у стринга есть свой джоин.
                        Облажался номер два. :(
                        Ответить
                        • Честно говоря, я совсем не то хотел показать в примере, куда комментарии пошли. Суть в том что я очень часто встречаю в коде сборку строчек через циклы с вставкой разделителя, ВМЕСТО того чтобы просто использовать string.JOIN(). Это ключевой момент.
                          Ответить
                          • Я понял. А я когда писал свой первый пост, просто сомневался, что это хороший выход. И ключевой момент моего недовольства, был IEnumerable вместо простого Dictionary или IDictionary, кодировка, культура.
                            Кстати насчет кодировки, может быть можно было закодировать весь шаблон сразу? Вто так: HttpUtility.UrlEncode("{0}={1}") Так и кей и валью сразу же.
                            или нельзя?
                            Ответить
                            • Вы точно понимаете, зачем нужен энкодинг? Я уже приводил пример POST-формы, а нормальные браузеры позволяют просматривать тела и заголовки входящих/исходящих запросов, можете посмотреть, что должно происходить.
                              Ответить
                              • Да, что бы избежать использование недопустимых знаков в урле.
                                Но как это относится к шаблону? Строку же можно создать форматом и в самом UrlEncode.
                                Ответить
                                • А что будет, если я захочу передать другой URL в качестве одного из параметров запроса? Заменяет ли UrlEncode знаки : / & = ?
                                  Ответить
                                • Пусть key = "next", value = "index.php?id=2&t=3". Если сделать все правильно (экранируем key отдельно, а value отдельно) - получится вот такая строка: "next=index.php%3Fid%3D2%26t%3D3". А если заэкранировать ее целиком, сэкономив один вызов, получится вот такая хрень, которую сервер, конечно же, не сможет распарсить: "next%3Dindex.php%3Fid%3D2%26t%3D3".

                                  P.S. А если распарсит - то это очень плохой сервер, поощряющий говнокод.
                                  Ответить
                    • У стринга свой труъ -джоин, а не линковый

                      Да тут и по вызову понятно - линк вызывается от коллекции, которую нужно обработать, а не статично
                      Ответить
              • Кто хочет быстрее - пусть пишет на ассемблере
                Ответить
                • > пусть пишет на ассемблере
                  На си хотя бы. Но многие программисты на шарпах, пыхах и прочих высокоуровневых языках, к сожалению, думают, что если они будут делать нанооптимизации типа замены " на ' или сложения двух-трех строк через стрингбилдер, то вся программа по волшебству начнет работать быстрее...
                  Ответить
                  • Основам оптимизации обучены единицы, потому всем остальным приходится пользоваться древними легендами и не менее древними мифами.
                    Ответить
                  • Один раз я видел как человек хранил обходы графа в виде стринга из номеров вершин и при этом занимался нанооптимизацией циклов.

                    А вообще в VS 12 есть тесты производительности которое сами покажут тебе узкие места программы , но, почему-то, ими никто не пользуется
                    Ответить
                    • Профайлеры для ленивых лохов, которым лень микрооптимизировать весь код.

                      Ну и еще, наверное, сказывается то, что про профайлер надо еще узнать...
                      Ответить
                      • Если учить программировать по MSDN, то про Linq, делегаты, лямбды можно узнать только чисто случайно.

                        Раз пошла такая тема... Кто откуда черпает знания о шарпике?
                        Я вот сейчас читаю "C# 4.0 и платформа .NET4 для профессионалов" - отличная книга.
                        Ответить
                        • Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.0 на языке C# (3-е издание, 2012), настоятельно рекомендую
                          Ответить
                          • Тоже о ней думал, можно сказать мечтал)
                            Ответить
                          • Для шарпа нужен только Рихтер.
                            Ответить
                            • Нельзя изучать что то по одному источнику.
                              Ответить
                              • Можно. ;)
                                Ответить
                                • Притча о слоне

                                  Четверо слепых подошли к слону. Один дотронулся до ноги слона и сказал: «Слон похож на столб». Другой дотронулся до хобота и сказал: «Слон похож на толстую дубину». Третий дотронулся до живота слона и сказал: «Слон похож на огромную бочку». Четвёртый дотронулся до ушей и сказал: «Слон похож на большую корзину». И потом они начали спорить между собой относительно того, каков слон.
                                  Ответить
                                  • Притча о нубе. Пришел нуб на говнокод и стал притчи рассказывать.
                                    Конец!

                                    Это просто шутка. :)
                                    Ответить
                                    • Ну почему же нуб - зарегистрирован уже 3 месяца как)
                                      Ответить
                        • > Кто откуда черпает знания о шарпике?
                          С говнокода :) Мое знакомство с шарпиком, к сожалению, началось и закончилось лет 8 тому назад... С тех пор я им толком и не занимался.
                          Ответить
                  • Это не оптимизации, это что бы мусора не было.
                    Хотя две - три строки нормальный шарпей запилит в шаблон.
                    Ответить
                    • > это что бы мусора не было
                      Избавление от мусора это, внезапно, оптимизация. В данном случае - микрооптимизация. Т.к. параметров у запроса всяко не так уж и много, а прилетевший ответ и его парсинг напрягут кучу посильнее, чем этот жалкий килобайт.
                      Ответить
            • builder.append(string.format("&{0}={1}", key, val));

              Вот, что вы делаете для каждого элемента, больше ничего.

              >>решарпер вообще тут ни при чем
              Он у меня стоит и тоже подсказывает подписать вместо Dictionary, Ienumerable.
              Ответить
    • А УРЛЭнкоде знаки равенства тоже заэкранирует как-то? Чет я не уверен, но пробовать влом.
      Ответить
      • Заэкранирует. Иначе параметры, в которых есть "=", ломали бы URL.
        Ответить
    • А через GetEnumerator() не получилось бы читабельнее? Минус несколько строчек кода как минимум. Не могу сказать про производительность.
      Ответить
    • Какой-то неосилятор минуснул код, гк же очевиден.
      Ответить
    • А Key разве не надо прогонять через UrlEncode ?
      Ответить
    • "неосилятор, не нравится" - предложите лучшее решение чем мое, я с удовольствием приму на вооружение. Код не девка, должны быть аргументы к слову "не нравится". Прогоны производительности показали увеличение скорости в 47 раз, не говоря уже о том что в первом варианте совершенно никакого понимания статичной природы строк в C#, с вытекающими последствиями - куча мусора в памяти.
      Ответить
      • А мне не нравится!
        Ответить
        • Простите, но http://lurkmore.to/%D0%92%D1%81%D0%B5%D0%BC_%D0%BF%D0%BE%D1%85%D1%83%D0%B9.
          Ответить
        • А баба яга против!)

          Критикуешь - предлагай, предлагаешь - делай
          Ответить
    • string.Format - можно ставить крест на производительности.

      Аффтор, хочешь быстрый код - избавься от string.Format. Простая конкатенация строк намного быстрее.
      Ответить
      • Вот единственный качественный ответ мне, большинство просто бред несут, не понимая вообще темы, уж извините за резкость. Итак! вот последняя редакция метода:
        static string BuildPostData(IEnumerable<KeyValuePair<s tring, string>> d)
        {
        return string.Join("&", d.Select(i => i.Key + "=" + HttpUtility.UrlEncode(i.Value)));
        }
        Тесты показали прирост производительности на 33%. Guest - Вам респект.
        Ответить
        • И код даже понятнее и проще стал, когда формат убрали.
          Ответить
        • >>в первом варианте совершенно никакого понимания статичной природы строк в C#, с вытекающими последствиями - куча мусора в памяти.
          >> i.Key + "=" + HttpUtility.UrlEncode(i.Value)
          Это юмор такой?
          Ответить
          • neeedle, у Вас очень плохо получается умничать.
            Ответить
            • Конкатенация порождает лишние строки? Порождает.
              Лишние строки может убрать только сборщик мусора.
              Чем больше вызовов сборщика мусора, тем больше убытки производительности.
              Это написано в CLR via C#, которую вы читали.
              Почему вы сейчас от своих слов отказываетесь, увидев, что плюсик сделает ваш миленький код быстрее, непонятно.
              Ответить
              • Кроме того что код оставляет мусора в разы меньше чем первый вариант, при этом Вы забываете о фоновой сборке мусора в отдельном потоке, так что убытков производительности тут практически нет, с учетом того что параметров обычно немного. Я указывал на то что использование string.Join ускорило код в 47 раз, использование конкатенации ускорило новый вариант еще на 33%. needle, Вы вообще чего добиваетесь? Предложите ЛУЧШИЙ вариант или Вы из армии евнухов, критиков и советчиков? Которые сами ничего не могут но комментируют все подряд что предлагают люди? Где Ваша реализация или Вы вообще код не пишете?
                Ответить
                • Сколько обычно параметров?
                  Я все еще думаю. Мне еще не доводилось строить в шарпе тело пост запроса в ручную, я всегда просто указывал параметры и отправлял запрос и смотрел что ушло, что пришло.
                  Ответить
              • А Format не порождает?)

                Плюс там милейшее S+= в цикле, что создает i строк в куче с арифметически прогрессируемым размером.

                Join сначала все подстроки сделает, а потом сливает
                Ответить
                • В смысле Join работает с коллекцией и сразу выделяет память под всю строку, а коллекция будет кошерно сгенерированна Select
                  Ответить
                  • Где такое указано? Ткните носом.

                    Насчет формата:
                    Кроме литерала шаблона, нет не должен.
                    Ответить
                    • А по вашему join конкотинирует их сложением в цикле? Бред же.

                      Думаю там стрингбилдер
                      Ответить
                      • код от мелкософта

                        StringBuilder result = new StringBuilder();
                        if (en.Current != null) {
                        result.Append(en.Current);
                        }

                        while (en.MoveNext()) {
                        result.Append(separator);
                        if (en.Current != null) {
                        result.Append(en.Current);
                        }
                        }
                        return result.ToString();
                        Ответить
                        • Я ничего не думаю, я просто просил, что бы вы мне показали, где такое говорится.
                          Ответить
    • Фейл оригинального кода в вызове linq'ового ElementAt к словарю: это даёт O(n) доступ.

      static string foo(IDictionary<string, string> d)
      {
          var s = "";
          int i = 0;
          foreach (var key in d.Keys)
          {
              if (i > 0) s += "&";
              s += key + "=" + HttpUtility.UrlEncode(d[key]);
              i++;
          }
          return s;
      }
      Ответить
      • Мне тут конкатинация в цикле не лстит.

        Она же в бинарной куче создаст i стрингов. Если словарь из 3 записей еще ничего. но если из 1000...
        Ответить
        • Естественно, если записей много, то переходим на StringBuilder.
          Ответить
      • Как то так....

        static string foo(IDictionary<string, string> d)
        {
        var s = new StringBuilder();

        foreach (var key in d.Keys)
        s.Append(key + "=" + HttpUtility.UrlEncode(d[key]) + "&");

        return s.Remove(s.Length-1,1).ToString();
        }


        Ибо делать итератор и условие в цикле лишь для того что бы исключить первый амперсант - богомерзко
        Ответить
        • s.Append(key + "=" + HttpUtility.UrlEncode(d[key]) + "&");
          facepalm.jpg
          Конкатенация никуда не делась...

          s.Append(key).Append('=').Append(HttpUtility.UrlEncode(d[key])).Append('&');
          Ответить
      • А вообще в d.Keys порядок элементов не определен, если порядок в словаре важен - не годится.
        Ответить
        • Дык, при любом способе так будет. Раз уж используется словарь.
          Ответить
    • static string BuildPostData(IDictionary<string, string> dictionary) {
          LinkedList<int> host = new LinkedList<int>();
          int shift = 0;
          int listLength = 0;
          int q = 0;
          foreach (KeyValuePair<string, string> entry in dictionary) {
            int i = 0;
            int sep = '=';
            string key = entry.Key;
            string value = HttpUtility.UrlEncode(entry.Value);
            string head = key;
            int state = 0;
            while (i < head.Length && state < 2) {
              int b = head.Length - i;
              int a = 4 - shift;
              if (shift > 0) {
                if (a > b) {
                  while (b-- > 0) {
                    q <<= 8;
                    q |= head[i++];
                    shift++; }
                  goto L1;
                } else {
                  while (a-- > 0) {
                    q <<= 8;
                    q |= head[i++];
                    shift++; }
                  goto L2; }
              } else {
                if (b > 3) {
                  b = 4;
                  while (b-- > 0) {
                    q <<= 8;
                    q |= head[i++]; }
                  goto L2;
                } else {
                  while (b-- > 0) {
                    q <<= 8;
                    q |= head[i++];
                    shift++; }
                  goto L1; } }
              L1:
              q <<= 8;
              q |= sep;
              shift++;
              sep = sep == '=' ? '&' : '=';
              i = 0;
              state++;
              goto L3;
              L2:
              if (i == head.Length) {
                listLength++;
                q = 0;
                goto L1; }
              L3:
              shift &= 3;
              if (shift == 0) {
                host.AddFirst(q);
                listLength++; }
              head = state == 0 ? key : value; } }
          string result;
          byte[] buffer = new byte[listLength * 4];
          using(BinaryWriter writer = new BinaryWriter(new MemoryStream(buffer))) {
            foreach (int octet in host) writer.Write(octet);
            result = System.Text.Encoding.Default.GetString(buffer.Reverse().ToArray()); }
          return result; } }

      Я думаю, парни, вы слабо оптимизировали, надо было сильнее оптимизировать.
      Ответить
      • Нужно бооольше оптимизации

        В студию код на ассемблере
        Ответить
      • Да уж, этот пиздец код заслуживает отдельного топика. Ловите плюс ;)

        > head = state == 0 ? key : value; } }
        > return result; } }
        Лисп головного мозга ;)

        > host
        Причем тут хост? Тут же query string собирают.

        P.S. Что-то мне намекает, что этот "оптимизированный" код будет работать медленнее чем исходный. Да и линкед лист из интов (если он однонаправленный), если я не туплю, сожрет втрое больше памяти чем обычная строка (ссылка на следующий, значение, тип объекта для GC в каждой ноде).

        P.P.S. Раз уж черезжопострингобилдер свелосипедили, то стоит и UrlEncode свелосипедить и заинлайнить руками ;)
        Ответить
        • Код такой потому что лимит символов в сообщении.
          Будет ли он медленнее - а это вообще важно? При всех остальных показателях. Я так думаю, что код просто замечательный, и вне зависимости от скорости нужно использовать именно его, а не какое-нибудь другое решение.
          Ответить
        • ЗЫ. Кроме всего прочего - кусок не влез, и если количество символов в результирующей строке не кратно 4, то остаток пропадет. Но просто никак больше сократить не получалось.
          Ответить
          • > кусок не влез
            pastebin, ideone
            Ответить
            • Код просто такой неоценимый, что его нужно было обязательно увековечить продублировав на всех ресурсах позволяющих это сделать. А лучше - разослать курьерской почтой всем заинтересованным.
              Ответить
        • ЗЫЫ. Хост здесь используется в его исконном значении "тьма" (в смысле "и тьма их", i.e. им несть числа).
          Ответить
          • Отсыпете мне того, что курите? :)
            Ответить
            • From The Collaborative International Dictionary of English v.0.48 [gcide]:
              
              Host \Host\ (h[=o]st), n. [OE. host, ost, OF. host, ost, fr. L.
                 hostis enemy, LL., army. See Guest, and cf. Host a
                 landlord.]
                 1. An army; a number of men gathered for war.
                    [1913 Webster]
              
                          A host so great as covered all the field. --Dryden.
                    [1913 Webster]
              
                 2. Any great number or multitude; a throng.
                    [1913 Webster]
              
                          And suddenly there was with the angel a multitude of
                          the heavenly host praising God.       --Luke ii. 13.
                    [1913 Webster]
              
                          All at once I saw a crowd,
                          A host, of golden daffodils.          --Wordsworth.
                    [1913 Webster]
              Ответить

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