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

    +137

    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
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    using System;
     
    class TLockCriticalSystemResource : IDisposable
    {
            public TLockCriticalSystemResource(){Console.WriteLine("Acquire critical system resource");}
            public void Dispose(){Console.WriteLine("Release critical system resource");}
            public bool Property1{private get{return true;}set{throw new Exception();}}
    }
     
    public class Test
    {
            public static void Main()
            {
                    using (var file = new TLockCriticalSystemResource()
                            {
                                    Property1=true
                            })
                    {
                        // Делаем чего-то с ресурсом
                    }
            }
    }

    Ололо. using не даёт гарантию безопасности с точки зрения исключений:
    http://ideone.com/nHDIJ
    Системный ресурс остался захваченным.

    Запостил: LispGovno, 17 Октября 2012

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

    • Где здесь lisp, LispGovno?
      Ответить
    • Опять порадовал.
      Кстати всегда хотел сделать так:
      http://ideone.com/9vnk2
      Ответить
      • А в жабе оказывается умнее сделали:
        http://ideone.com/2DaQ7
        java.lang.RuntimeException: work error!
        	Suppressed: java.io.IOException: close error!

        Но c изначальным примером та же трабла:
        http://ideone.com/BJWuu
        Ресурс считается неинициализированным.

        Но мне то что? Я по-старинке пишу:
        Resource res;
        try{
           res=new Res();
        }finally{
           res.close();
        }
        считая это всё сахаром. Во многих случаях в finally надо еще что-то делать.

        Главное не секономить тут строку кода, а красиво это обернуть его в что-то удобное.
        Ответить
    • Не дает — об этом Липпет тоже писал.
      Ответить
    • using появился в .net 1.1. object initializers, который был использован выше - в 3.0. Если почитать про них, и посмотреть что он генерит, то понятно почему так происходит. А если тупо использовать где попало, то да, будет лажа.

      А проблема в том, что код выше генерится в такую конструкцию

      TLockCriticalSystemResource _tmpObj = new TLockCriticalSystemResource();
      _tmpObj.Property1 = true;
       using (var file = _tmpObj)
      {
                          // Делаем чего-то с ресурсом
      }

      который станет -

      TLockCriticalSystemResource _tmpObj = new TLockCriticalSystemResource();
      _tmpObj.Property1 = true;
      
      TLockCriticalSystemResource file;
      try
      {
      	file = _tmpObj;
      	// Делаем чего-то с ресурсом
      }
      finally
      {
      	if (file != null) file.Dispose();
      }

      Поэтому и нельзя использовать object initializers вместе с using-ом
      Ответить
      • >Поэтому и нельзя использовать object initializers вместе с using-ом
        Но при этом это компилируется. Ололо. ШАРПАПРОБЛЕМЫ

        Если using раскрывается таким образом (я надесь, что не так), то у меня для него плохие новости:
        TLockCriticalSystemResource _tmpObj = new TLockCriticalSystemResource();
        _tmpObj.Property1 = true;
        //А здесь мы кинули исключение ThreadAbortException через thread1.Abort() в асинхронном потоке.
        TLockCriticalSystemResource file;
        try
        {
        	file = _tmpObj;
        	// Делаем чего-то с ресурсом
        }
        finally
        {
        	if (file != null) file.Dispose();
        }
        Ресурс снова утёк.
        Ответить
        • толсто. проблемы кривых рук не должны быть проблемами компилятора.

          ЗЫ. Abort кагбы не рекомендуется использовать, ибо поток должен завершаться сам. Насколько я помню, они хотели избавится вообще от Abort метода.
          Ответить
          • >толсто. проблемы кривых рук не должны быть проблемами компилятора.
            Как шарпеи увидять проблему кривых рук в С++, так сразу кричат - крестопроблемы, кресты говно. А как увидят в шарпе - криворук ниасилятор, язык и компилятор шарпа же - невинны.
            Что-за двойные стандарты?
            Ответить
            • я лично так не кричу. у каждого языка свои плюсы и минусы(а у некоторых даже два плюса :)).
              И для разных задач можно использовать разные языки, и при этом выбирая нужно знать как о плюсах, так и о минусах. А не просто использовать язык, ибо это "модно".
              Ответить
              • >>>толсто. проблемы кривых рук не должны быть проблемами компилятора.
                >я лично так не кричу
                Ответить
                • В чем связь двух комментов? Конкретно это проблема object initializer, и как я уже сказал, их не рекомендуется использовать в using-ах. С точки зрения языка все корректно и поэтому компилится. Это не java, компилятор не может знать выкинется там exception или нет, и он оставляет это на девелопера.

                  MS говорил о том что так делать не рекомендуется.

                  PS. Я разве где-то что-то кричал на C++?
                  Ответить
                  • > Я разве где-то что-то кричал на C++
                    > кричал на C++
                    О. Это безблагодатное занятие. С++ вас врятли поймет.
                    Ответить
          • Запрет абортов. Еще одна тема, вышедшая из узких программерских кругов.
            Ответить
        • Там множество проблем. Для гарантированного освобождения ресурсов следует использовать либо CriticalFinalizerObject, либо CER.
          Ответить
          • >Там множество проблем
            Какие ещё?

            >следует использовать CriticalFinalizerObject
            Он заставляет обязательно вызывать финализатор во время сборки мусора. Не о каких Dispose и речи не идет. Да и сборка мусора может произойти (и сделает это) через недетерминированное время.
            Ответить
            • Да, но вы получите гарантированную очистку, хоть и не детерминированную.
              Ответить
              • Недетерменированная очень редко нужна. Обычно нужна детерминированная.
                Ответить
                • В таком случае не надо делать Thread.Abort, выкидывать исключения в конструкторе после того, как вы захватили неуправляемый ресурс (а если вам это необходимо — освободите перед этим ресурс вручную) и использовать дополнительные инициализаторы, которые не являются exception-safe.

                  Тогда using будет работать гарантированно так, как задумывался.
                  Ответить
                  • Да да да. Проследи за всем сам, за каждым подчинённым, а чтоб точно нигде ничего не пропустить - лучше найми очень хорошего дорого оплачиваемого ревьювера кода. Конечно, ведь поправить using или хотябы запретить инициализатор в using - мс не осилила.
                    Ответить
                    • В инициализаторе в using в общем случае ничего плохого нет — там могут быть вполне банальные присваивания безо всяких исключений.

                      Запрещать только из-за того, что недалекие разработчики могут выстрелить себе в ногу... простите.
                      Ответить
              • >но вы получите гарантированную очистку, хоть и не детерминированную.
                Ну и нахер оно такое надо?
                Коннекшен пул на БД весь занят.
                И пользователи ждут неопределенное когда GC освободит хотя бы одно соединение. Шикарно.

                >для гарантированного освобождения ресурсов следует использовать
                У нормально написанных классов dispose вызывается из деструктора и finalize().

                http://reflector.webtropy.com/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/IO/FileStream@cs/1305376/FileStream@cs

                См. ~FileStream()
                Ответить
                • > Ну и нахер оно такое надо?
                  Поддерживаю. "Гарантированное" освобождение ресурса даже через несколько секунд (если коллектор периодически запускается в свободное время, дабы собирать эти потерянные ресурсы) нахуй никому не нужно.
                  Ответить
          • >либо CER
            Поподробнее?
            Ответить
      • Спасибо кеп.
        И причем тут инициализаторы? Я могу написать и так:
        using (var file = new TLockCriticalSystemResource().withProp1(true))

        >fluent метод withProp1 кинет исключение.

        Гумно прав в основном. В том что в using есть дырка. Инициализаторы здесь ни при чем.
        Ответить
      • >object initializers, который был использован выше - в 3.0
        Вот я набросал грубый пример где происходит утечка безо всяких инициализаторов, но с зависимыми ресурсами.
        Случай вполне типичный из Connectionа получаем Statement, а из него ResultSet.

        http://ideone.com/ZvmIO
        Если при освобождении Statementа - упало, соединение не освободили.
        class DepResource : IDisposable
        {
                public DepResource(){Console.WriteLine("Acquire DepResource");}
                public void Dispose()
                {
                        Console.WriteLine("Release DepResource");
                        throw new Exception("Sir, some shit was happen while releasing DepResource");
                }
        }
         
                                IDisposable res2;SystemResource res1;
                                using (res2=(res1 = new SystemResource()).dependentResource() )
                                {
                                    Console.WriteLine("Do my work");
                                }
        Ответить
        • Да, согласен, object initializer только один из примеров. Причина в том что вызов конструктора и dependentResourse происходит до входа в try блок.
          Ответить
          • То понятно.
            >Причина в том что вызов конструктора и dependentResourse
            Стоп. Но я же в using все конструкторы написал.
            Ни о каких try я не знаю, я ведь специально пишу using, чтоб не писать try.
            По-нормальному должно освобождаться.
            Ответить
            • http://msdn.microsoft.com/en-us/library/yh598w02.aspx
              Там на примере написано во что оно разворачивается. Если бы те кто используют using читали бы это, они бы знали об этом. Просто использовать using незная как он работает в действительности надеясь на "всемогущий фреймворк" как-то глупо.

              Почему так, нужно поискать у Липперта. Он рассказывал причину, почему они так сделали.
              Ответить
              • Мне понятно как оно работает. Я еще вчера напейсал:
                http://govnokod.ru/11950#comment156393
                //Я по-старинке пишу:
                Resource res;
                try{
                   res=new Res(); //внимание! конструктор в try
                }finally{
                   res.close();
                }


                Конечно кидать исключения из конструкторов и инициализаторов некошерно. Но!
                А если у нас там стоит какой-то Wait, который ожидает пока придет Pulse с другого потока - "ресурс освобожден поцоны! "

                И тут в наш тред внезапно врывается ThreadInterruptedException.
                Ответить
    • Судя по последним постам LispGovno, он добрался до блога Сергея Теплякова. И, основываясь на приведённых там описаниях, создаёт свои говнокоды.
      В частности, этот пост создан по мотивам http://sergeyteplyakov.blogspot.com/2012/05/using.html
      Так?
      Ответить
      • Скоро вирус доберётся до Пентагона и тогда мир окажется в ядерной опасности!
        Ответить
        • Stuxnet, duqu, flame, gauss ... LispGovno - эволюция добралась до правого края латинской раскладки.
          Ответить
        • Язык до Пентагона доведет
          Ответить
      • > И, основываясь на приведённых там описаниях, создаёт свои говнокоды.
        Да это не новость, что Гумно ничего своего не придумывает - как и положено гумну он копипастит чужое.
        Так ведь с самого начала было. Только год назад он пастами всё закидывал. Другое дело что теперь до него наконец дошло, что сайт называется ГовноКод. И он постит код. Это большой прогресс между прочим.

        Ну и похер что этот код где-то уже был, тут ведь не было. А именно тут ему самое место. Поэтому Гумно и получил плюс.
        Ответить

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