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

    +136

    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
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    class Program
        {        
            class A
            {
    
                //-----------------------------------------------------------------------
                public static A CurrentRoot;
                public static Dictionary<object, A> RootMap = new Dictionary<object, A>();
                public static object Lock = new object();
                //-----------------------------------------------------------------------
    
                public int Test;
    
                public A()
                {
                    lock (Lock)
                    {
                        CurrentRoot = this; 
                        b = new B();
                    }   
                }   
                internal class B
                {
                    public B() { RootMap.Add(this, CurrentRoot); }
    
                    public A root { get { return RootMap[this]; } }                
    
                    ~B() { RootMap.Remove(this); }                
                }
                public B b;
            }
         
            static void Main(string[] args)
            {
    
                A a1 = new A(); a1.Test = 555;
                A a2 = new A(); a2.Test = 888;
    
                Console.WriteLine(a1.b.root.Test); Console.WriteLine(a1.Test);
                Console.WriteLine(a2.b.root.Test); Console.WriteLine(a2.Test);
    
    
                Console.WriteLine(a1.b.root.b.root.b.root.b.root.b.root.Test);
            }

    Класс создан для того чтобы вложенные структуры имели доступ к структуре родителя. Safe thread support.

    Запостил: maxillion, 20 Сентября 2014

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

    • > вложенные структуры имели доступ к структуре родителя

      меня убивает что ни один язык/фрэймворк не позволяет этого сделать из коробки.

      только не надо мне опять эти теории толкать что это "теоретически неправильно".

      на практике бывает нужно, и доморощеные реализации часто обращаются в ГК монументального характера.
      Ответить
      • можно пример когда "ну очень надо"?
        Ответить
        • интелектуальные компоненты, внутри иерархических систем, которым для оптимальной производительности, или воркараунд хардварных багов, или увдовлетворения внешних требований, нужно знать их место в иерархии объектов. (это буквальное, дословное (но абстрагированое) описание двух "монументальных" ГК с которыми мне приходилось работать в прошлом.)

          повседневные примеры тоже легко найти.

          возьми любую GUI библиотеку. каждый раз когда ты создаешь контрол, ему параметром надо передать парент окно. теоретически, контролу парент в ж не нужен. но практически, контрол наследует бэкграунд от парента, рисует себя в контексте парента, и получает события от парента.
          Ответить
          • > возьми любую GUI библиотеку
            Пример не очень ИМХО, т.к. предок контрола рисует свой фон и контрол. А контрол просто уведомляет, что он "грязный" и его нужно перерисовать. Да и знать структуру родителя контролу тоже незачем.

            Мне этот "доступ вложенной структуры к структуре родителя" напоминает сишный offsetof. Вроде, полезный, но хак.
            Ответить
            • > сишный offsetof

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

              offsetof() как раз и не работает, потому что нужно знать заранее что во что вложено. иначе не работает.
              Ответить
              • > и да и нет. проблема в том что бы вложеная структура могла узнать что (1) она вложеная, (2) и если она вложеная то во что.
                struct Struct {};
                struct Parent {
                    Struct a, b; // (3) а если вложений несколько, то тоже как-то разобраться с этой фигнёй.
                };
                Я почти уверен, что в языке D есть конструкция, удовлетворяющая всем требованиям, да ещё и в compile time.
                В шарпике мб через рефлексию можно что-то соорудить.
                Ответить
                • я случайно трогал рефлексию в жабе. интерфейс как всегда жутко примитивный, но с 2-3 фреймворками, может быть и можно будет что-то соорудить.

                  преимущество жабы (и шарпа?) здесь в том что объект есть всегда указатель. в крестах же есть еще грабли что у тебя вложеная структура может быть (1) частью родительского объекта, или (2) родитель может на нее иметь только указатель.
                  Ответить
        • а и да. одна из самых большых проблем это то отсутствие такого механизна не позволяет создавать такие иерархии статически. только динамически.
          Ответить
      • > на практике бывает нужно
        Почему бы просто не передать ссылку на родителя в конструктор?
        Ответить
        • представь себе класс/структуру с ~50 полями.

          `static StaticEntity static_entity;` - и у тебя все 50 полей проинициализированы нулями. не идеально - но работает.

          теперь представь себе теперь добавление конструктора, и последующее добавление 50 инициализаторов для этих полей. и это все только что бы передать один гребаный параметр - который к слову компилеру известен.
          Ответить
          • Т.е. идея вот такая?
            1) Помечаем класс как "имеющий ссылку на его владельца". От этого у него внутри появляется неявный указатель некого типа, а у конструктора возникает неявный параметр.
            2) Экземпляр данного класса нельзя использовать без владельца (т.е. размещение на стеке или через new запрещено (как вариант - разрешено, просто указатель будет null'ом, еще вариант - можно самому передать как параметр в new или конструктор).
            3) Владелец, во время конструирования, передает туда указатель на себя. При этом, если тип владельца не кастуется в тип неявного указателя - возникает ошибка компиляции.
            4) Теперь объект может юзать неявный указатель на владельца, при необходимости раскастовывая его во что нужно.

            > все 50 полей проинициализированы нулями
            Имхо, зависеть от способа создания объекта - ССЗБ. Сегодня он в статике, и там нули. Завтра его создали на стеке или в куче - и кровь-кишки-распидорасило. Я сразу бы написал 50 инициализаторов, чтобы спать спокойно.
            Ответить
          • В Лиспе хоть с этим проблем нет. Можно в описании класса указать какие поля нужно инициализировать прямо при создании, а какие можно не трогать / инициализировать значениями по-умолчанию. Такую вещь как создание только в контексте другого класса можно, например, описать мета-классом.
            Ответить
            • В крестах тоже можно не писать явные инициализаторы. Для нормальных классов сработает конструктор по-умолчанию. А вот примитивы останутся мусором (впрочем, иногда так и надо, ради скорости).
              Ответить
    • че я не понял нафиг запись в статичную коллекцию особенно здесь. И финализатор убивает - удаленные ссылки на обьект из метода, который запускается только тогда, когда на этот объект гарантированно нет ссылок

      в данной ситуации данный код отсасывает простому

      internal class Program
          {
              class A
              {
      
                  public int Test;
                  public B B { get; private set; }
                  public A()
                  {
                      B = new B(this);
                  }
      
              }
      
              class B
              {
                  public A Root { get; private set; }
                  public B(A root)
                  {
                      Root = root;
                  }
      
              }
              private static void Main(string[] args)
              {
      
                  A a1 = new A();
                  a1.Test = 555;
                  A a2 = new A();
                  a2.Test = 888;
      
                  Console.WriteLine(a1.B.Root.Test);
                  Console.WriteLine(a1.Test);
                  Console.WriteLine(a2.B.Root.Test);
                  Console.WriteLine(a2.Test);
      
      
                  Console.WriteLine(a1.B.Root.B.Root.B.Root.B.Root.B.Root.Test);
              }
          }
      Ответить
      • А если у меня несколько сложных вложенных структур правка которых не допустима, и я хочу считывать их через указатель одним разом. Тогда при добавление лишнего поля чтение через указатель становится не возможным. И тогда твой метод в котором придется для хреновой тучи структур создавать конструктор чтения, будет выглядеть нелепо.
        Ответить
        • Мне кажется или ты херню несешь? Скажи нормально
          Ответить
          • Как сюда добавить твой рут при условии что размер структур меняться не должен.
            class Program
                {
                    public struct B
                    {
                        public int x;
                    }
                    public struct A
                    {
                        public int x;
                        public B b;
                    }
                    unsafe static void Main(string[] args)
                    {
                        FileStream fs = File.Open("", FileMode.Open);
                        byte[] buff = new byte[sizeof(A)];
                        fs.Read(buff, 0, buff.Length);
            
                        fixed (byte* p = buff)
                        {
                            A* pA = (A*)p;
                            Console.WriteLine(pA->b.x);
                        }            
                    }
                }
            Ответить
            • А теперь скажи - как ты вообще к этому пришел?

              Рут лежит в B, а идешь ты по массиву А.

              И даже если бы шел по массиву B какая разница сколько полей если ты размер задаешь не руками а получаешь рефлексией?

              Почему бы не юзать сериализацию?
              Ответить
        • Это высер местного бота.
          Ответить
        • "А если у меня несколько сложных вложенных структур правка которых не допустима.." "Тогда при добавление лишнего поля.."
          Ты сам то понимаешь что ты говоришь? Сам себе противоречишь. Если ты имел ввиду что при создании сложных вложенных структур ты хочешь иметь к ним доступ, не прибегая к бесконечным итерациям по коллекциям, то юзай фабрику в которой будут храниться в каком то виде иерархия созданных объектов
          Ответить
    • И кстати простым но не полным решением этой проблемы может разрешение "namespace" в структуре
      struct A
      {
      	int x;
      	namespace B
      	{
      		int x;
      		namespace C
      		{
      			int x;
      		};
      	};
      };

      Не знаю почему такую простую вещь до сих пор не организовали.
      Ответить
      • Ну ты же не пихаешь свинарник в свиней, правильно?
        Ответить
        • а что ты пихаешь в свиней?
          Ответить
          • Других свиней, полиморфизм же.
            Ответить
            • Полиморфизм? Чет я не помню такого полиморфизма, что бы свиней в свиней совать
              Ответить
              • Ну я что сделаю?
                Ответить
              • А как по твоему свиньи размножаются? одна свинья пихает себя в другую. Да знаю звучит мерзко.
                Ответить
                • я думал хряк пихает в свинью.
                  Ответить
                  • я в этих тонкостях не разбераюсь кто из них свинья кто хряк кто боров. Я их всех заву свиньями. Не стоит еду узнавать ближе, так и до вегетарианства рукой подать.
                    Ответить
            • Яйцо в утке, утка в зайце, заяц в шоке.
              Ответить

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