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

    +130

    1. 1
    2. 2
    3. 3
    4. 4
    private static bool? GetBoolFromObject(object o)
            {
                return string.IsNullOrEmpty(o.ToString()) ? (bool?)null : (bool)o;
            }

    и как такое можно только писать...

    Запостил: testguru, 20 Июня 2011

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

    • return o as bool?;
      Ответить
      • минусователь плохо знает шарп
        Ответить
        • Хоть такой код и будет короче в IL (всего 12 байт), но он не учитывает передачу не bool.
          Соответственно, клиент получит null там, где должен был быть InvalidCastException.

          Самый кородкий код с проверкой на null выглядит так (13 байт):
          return (Boolean?)(o == null ? null : o);

          А вот использованный автором двойной explicit cast в нормальном исполнении займёт уже 25 байт:
          return o == null ? (Boolean?)null : (Boolean)o;
          Ответить
          • Ну, если уж быть точным, то ваш код тоже не эквивалентен коду в топике:

            1) оригинальный говнокод возвращает null для объектов, ToString от которых будет пустой строкой, а оба ваших варианта выбрасывают в таком случае InvalidCast.

            2) оригинальный говнокод падает с NullReference если o == null. Ваш - возвращает null.

            P.S. Что-за прикол выдрачивать байты из IL? Имхо, попахивает преждевременной оптимизацией аля "одинарные кавычки в PHP работают быстрее двойных".
            Ответить
            • Ответить
              • И опять, я с Вами полностью согласен по первым 2м пп.
                Меня больше заинтересовало поведение компилятора с 2мя explicit cast'ами в тернарном операторе, а не накладывания сверху оптимизированной кучи на существующую кучу.
                P.S. Что-за прикол выдрачивать байты из IL?
                Ну, это вопрос практики говнокоженья на шарпе, можно и StringBuilder не использовать, ведь String'а заглаза хватает. Или достаточно новый холивар "List vs Array" и т.п...
                Ответить
                • Имхо лучше выбрать более наглядный и понятный вариант, нежели тот, у которого IL короче (как ни странно - на вашем примере оба критерия совпали ;). А тонкие оптимизации оставить на случаи когда архитектура уже вылизана, поменять в ней нечего, а время работы все еще неприемлимо большое, но мы уже знаем места, где оно тормозит больше всего...

                  P.S. Это не относится к микроконтроллерам и другим прокрустовым ложам, в которых каждый байт и такт в цене.
                  Ответить
          • учитывает. если o присваиваемо к bool? то кастануть иначе null
            Ответить
            • Код:
              Object o="True";
              return (Boolean?)o;

              Свалится с InvalidCastException.
              При использовании ключевого слова as получаем null:
              Object o="True";
              return o as Boolean?;

              В результате получаем возможный "Mad girlfriend bug" где-то ниже по коду. Для примера:
              Object o="True";
              Boolean? res=GetBoolFromObject(o);
              ...
              if(res==null)//Продолжаем говнокодить, а abatishchev исправил метод на as.
                  Console.WriteLine("Не удалось скастовать значение "+o.ToString()+" o к флагу.");

              И в результате:
              1) Произойдёт ошибка NullReferenceException, а не InvalidCastException.
              2) Ошибка произойдёт не во время каста, а во время вывода сообщения, т.е. n строками ниже.
              Ответить
              • > "Не удалось скастовать значение "+o.ToString()+" o к флагу."
                Вот кстати в этом отношении жаба рулит. На ней это звучало бы так:
                "Не удалось скастовать значение " + o + " к флагу"
                и не крашилось бы ни при каких условиях ;)
                Ответить
                • В шарпе для этого есть конструкция:
                  Console.WriteLine(string format, object arg0)

                  Которую можно использовать, скажем, так:
                  if(res==null)
                      Console.WriteLine(Resources.warnCantCastArgs1, o);

                  А в ресурсах уже строка куда подставить значение. И если o==null, то будет пустая строка.
                  Аналогично String.Format(...).
                  Ответить
              • P.S. А вообще, имхо, оба варианта имеют право на жизнь:

                Вариант @abatishchev применим в случаях, когда неправильный тип это вполне допустимая ситуация, и ловить InvalidCast, а потом все-равно делать абсолютно то же самое, что и при null было бы неудобно и бессмысленно.

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

                Вот такое мое имхо.
                Ответить
                • >P.S. А вообще, имхо, оба варианта имеют право на жизнь:
                  Не соглашусь, кодинг на .NET'е рекомендует по любому поводу выбрасывать исключение, особенно если это метод, а не инлайн переменная, и если входной параметр такой абстрактный.
                  Как я понимаю, это связано с тем же WinAPI, где часть функций выбрасывало Exception, а часть модифицировали результатирующее значение, при появлении которого необходимо было читать GetLastError.
                  В свою очередь, использование GetLastError, я предполагаю, связано с тем, что директория Exception Table в PE файле появилась не так чтобы и давно, а вот CorILMethodSect, которая предоставляет аналогичную таблицу адресов, в толстом формате методов таблицы MethodDef были заложены в первую версию ecma-335.

                  А по поводу ключевого слова "as", у меня был опыт говнокодинга, когда я нарвался на подобный плавающий баг с бездумным использованием этого ключевого слова, после этого решил что лучше обработать first chance exception с явным преобразованием, а уже на лог-сервере, если это реально лишнее, отсеять CEP'ом.
                  Ответить
              • особенность оператора as в том, что сразу после него должна идти проверка != null, иначе его использование бессмысленно.
                Ответить
                • Ага. Но если вернуться к теме обсуждения, то:
                  return o as bool?;
                  проверка после return'а - бессмысленна. А в некоторых случаях (threat warnings as errors) даже не соберётся.

                  Речь была про минусовальщика, вот я и захотел объяснить за что минусователь поставил минусы. Заодно наткнулся на интересное поведение явного преобразования в тернарном операторе, что и попытался объяснить в своём первом посте в этой теме.
                  Ответить
                  • abatishchev, видимо, имеет в виду не поменять код внутри функции, а вообще убрать эту функцию, и заменить ее вызов на o as bool?. Тогда и проверка к месту, и все соберется.
                    Ответить
                    • Такой подход может породить проблему человеческого фактора, где после преобразования as надо не забыть написать if.

                      Хотя, если вообще убрать эту функцию, то проще заменить её на:
                      Boolean System.Convert.ToBoolean(Object value)


                      или так (если не нравится поведение метода ToBoolean при передаче value=null):
                      Object System.Convert.ChangeType(Object value, TypeCode typeCode)


                      Или даже так (Если не нравится отсутствие структуры Nullable<T> в .NET 1.1):
                      private static bool? GetBoolFromObject(object o)
                      {
                          if(o==null) retun null;
                      
                          IConvertible converter=o as IConvertible;
                          if(converter==null) return null;
                      
                          return converter.ToBoolean(System.Threading.Thread.CurrentThread.CurrentCulture);
                      }


                      А чтобы не писать лишнего кода, проше написать предложенный Вами вариант.
                      Код:
                      Boolean? value = (Boolean?)o;
                      if(value==null) {...}


                      будет короче аналогичного кода с использованием as:
                      Boolean? value = o as Boolean?;
                      if(value==null)
                      {
                          if(o!=null) throw new InvalidCastException("banana");
                          ...
                      }


                      Хотя и в таком случае можно получить NullReferenceException при обращении к свойству Value.
                      Так что самый красивый вариант будет проверить o на null, а затем уже делать преобразование:
                      ...
                      if(o==null) return;
                      
                      Boolean value=(Boolean)o;
                      ...
                      Ответить
          • P.P.S. Я конечно совсем не знаток шарпа, но разве ваш код не эквивалентен банальному return (Boolean?)o. Он же null и так корректно скастует...
            Ответить
            • Точно! Увлёкся тринарным оператором...
              По сравнению с Вами - я не знаток шарпа :)
              Ответить
              • > По сравнению с Вами - я не знаток шарпа
                Да ну бросьте ;) Я его никогда не учил даже... недельный не очень удачный опыт общения с шарпиком лет 6-7 назад, и созерцание шедевров на нем на ГК...

                Мне ближе c, c++ и, как не странно, жаба.
                Ответить
                • > Я его никогда не учил даже...
                  > созерцание шедевров на нем на ГК...
                  same shit.
                  Полагаю таким же образом Тарас выучил С++, годами обсирая его на крестофоруме.
                  Ответить
    • этож философский вопрос)) смотрите:
      мужская логика bool да/нет
      женская логика bool? да/нет/не знаю
      =)
      Ответить
    • дополнение - на вход функции передаётся значение которое всегда true or false запакованное в object.
      Ответить
    • Слёзы... Слёзы... Нет, это не горе это умиление :) Дело в том, что данный метод вернул меня во времена, когда я был маленьким и с непониманием и завистью смотрел на код в умных книжках. Меня всегда забавляли подобные опусы, они заставляют задуматься насколько сложный прибор это головной мозг и как некоторые им изысканно пользуются.
      Ответить
    • написал бы тест, нашёл бы ошибку при o=null

      ps
      рыдаю
      Ответить
    • (bool?)null
      тянет на отдельный говнокод )
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить

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