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

    +1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    // Не очень красивое решение. Но зато можно не выставлять в паблик всякие кишочки
    	private void SetValueToPrivateField<Type>(Type instance, string field, object value) {
    		if (instance != null) {
    			FieldInfo fieldInfo = typeof(Type).GetField(
    				field,
    				BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
    			);
    				if (fieldInfo != null) {
    				fieldInfo.SetValue(instance, value);
    			}
    		}
    	}

    Публичный сеттер нарушит инкапсуляцию, поэтому будем использовать рефлексию

    "Мне нельзя ничего есть, поэтому я вставлю себе трубку прямо в живот и буду при необходимости заливать прямо туда. Но есть не буду"

    Запостил: Caritas, 11 Марта 2015

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

    • > Публичный сеттер нарушит инкапсуляцию, поэтому будем использовать рефлексию

      Спасибо! Мой нынешний проект манагер хочет больше прайвитов - и прочих ОО фишек - и теперь я знаю как его идеи претворить в жизнь!
      Ответить
    • > зато можно не выставлять в паблик всякие кишочки
      А в шарпе разве нету какихнить friend'ов как в крестах или package private как в жабе? Чтобы доступ к кишочкам предоставить только ограниченному кругу близких друзей.
      Ответить
      • А как вообще решается проблема, когда есть класс Y, у него есть наборы методов a*, b*, c*, ..., есть классы A, B, C, ..., которым надо иметь доступ к a*, b*, c*, ... соответственно? ("*" - много)

        Я пока вижу примерно два варианта:
        1. Иерархиопуть. Запилить интерфейсы YA, YB, YC, ... c a*, b*, c*, ..., унаследовать от них Y и кастовать к Y*&. Но тогда придётся платить за виртуальные функции. Хотя, нет тут нужны в виртуальных функциях, я бы на месте компилятора их выпиливал.
        2. Питонопуть. Сделать a*, b*, c*, ... публичными. Написать в документации, что a* могут вызывать только A, b* - только B, c* - только C. Пирфоманс!
        3. Крестопитонопуть. Сделать a*, b*, c*, ... приватными. Задрузить A, B, C и написать в документации, что что a* могут вызывать только A, b* - только B, c* - только C. Наследники A, B, C соснут.

        Пример:
        class Computer {
        public:
          // User может:
          Computer(size_t mem, double freq);
          void enable(bool);
          void execute(const Program&);
          
          // Program может:
          void set_byte(size_t, unsigned char);
          void get_byte(size_t, unsigned char&);
          
          // Monitor может:
          void get_pixel(size_t, size_t, unsigned long&);
        };
        Ответить
        • >>А как вообще решается проблема, когда есть класс Y, у него есть наборы методов a*, b*, c*, ..., есть классы A, B, C, ..., которым надо иметь доступ к a*, b*, c*, ... соответственно? ("*" - много)

          интерфейсы же. приводить и обращаться
          2 и 3 - сатанизм чистой воды
          а вообще это скорее хреновая архитектура - богообъекты нинужны
          Ответить
          • Это не богообъекты. Это несколько тесно связанных объектов из одной либы.
            Ответить
            • Ну если это действительно необходимость а не плохая архитектура - из постановки задачи видно, что обьект должен иметь 3 различных вида поведения - то бишь интерфейсы. А KISS еще никто не отменял

              + если нужно различное поведение из схожих блоков действий - можно сделать над объеком 3 адаптера, дабы не нагружать его левыми, не нужными самому обьекту, методами
              Ответить
              • > можно сделать над объеком 3 адаптера
                Санитары, быстрее сюда! У пациента приступ ООПянки!
                Ответить
                • Именем Мартина Фаулера вы арестованы!
                  Ответить
              • 1024-- слишком раздул проблему. На самом деле задачка примерно так звучит: "несколько классов из текущего модуля должны иметь чуть больше доступа, чем весь остальной мир". Ну например DBConnection может создавать DBQuery, а все остальные - не могут.

                Это можно разрулить через интерфейсы и перекастовочки, да. Но это, имхо, оверкилл. Через friend'ов (c++), package private (java) или internal (c#) получается проще и приятней.
                Ответить
                • > Ну например DBConnection может создавать DBQuery, а все остальные - не могут.
                  Хуёвый пример, да. Тут хватит IDBQuery для клиентов и его реализации DBQuery, которую запиливает и настраивает DBConnection...
                  Ответить
                  • Прочитал зузика - исходеая задача должна была звучать как то так - как дать одним классам полный доступ к текушей подсистеме, а другим - частичный.

                    А у 1024-- как дать разным классам разные наборы функций
                    Ответить
                • Да хочется ограничить себя и других, чтоб не использовать чужое, но так, чтобы это ещё было удобно.
                  С интерфейсами надо выносить и дублировать сигнатуры, платить за виртуальные методы. С друзьями нельзя передать права наследникам. Без премудростей можно случайно наплодить зависимостей.

                  Вот было бы что-то типа
                  public A, private B, free C, public *:
                  // доступно классу A и его потомкам;
                  // доступно классу B, но не его потомкам;
                  // недоступно классу C
                  // доступно всем остальным;
                    int method1();

                  ...и зажили бы.
                  Ответить
                  • не надо, спасибо.
                    Ответить
                    • Если бы я был Бьярни, я бы вообще выпилил эти friend'ы, да сделал модификатор namespace private по аналогии с жабьим package private.
                      Ответить
                      • Поддерживаю.
                        Ответить
                      • Борманд, предлагаю объединиться, собрать машину времени, переместиться в прошлое и изобрести правильный C++ с move-семантикой и namespace-private раньше Бьярне.
                        Ответить
                        • Я предлагаю переместиться в прошлое и не изобретать с++
                          Ответить
                          • > и не изобретать с++
                            Убить Бьярни?
                            Ответить
                            • С бабой познакомить. Ну если он совсем валет - убить

                              И тогда ООП будет смолтолковское...
                              Ответить
                          • От того, что ты в прошлом не изобретёшь C++, ничего не изменится.
                            Ответить
                            • Зато я буду жить в мире без крестоблядей. Некоторое время.
                              Ответить
                              • Паскалебляди не чем не лучше.
                                Ответить
                                • Когда ты их в последний раз видел?
                                  Ответить
                                  • Как раз до крестов

                                    Видимо мутировали в крестоблядей (это что за покемон?..)

                                    (Тарас, это не про тебя, просто похоже получилось...)
                                    Ответить
                                  • > Когда ты их в последний раз видел?
                                    Я недавно видел в коридоре. Спокойные, бородатые дядьки, обсуждали, как удалить rad studio.
                                    Ответить
                                  • На фоне крестоблядей не видны. Убрать кресты и начнется. "Мой паскаль круче твоего."
                                    Ответить
                                • Бляди... Везде бляди...
                                  Ответить
                      • Хотя я тут подумал - package private реально нужен только для хедер-онли либ.

                        Ибо внутренние кишки я всегда могу запимплить, а приватные структуры и методы, нужные в нескольких модулях, тупо не выставлять наружу из динамической либы.
                        Ответить
                  • > С друзьями нельзя передать права наследникам.
                    Ибо нехуй. У тебя ИРЛ тоже дружба по наследству передаётся?
                    Ответить
                    • Дружу семьями :)
                      Говно же. Надо делать как с обычными методами. К приватным друзьям добавить публичных. Запилил я интерфейс фигни, которая мне заполняет объекты смыслом, кто-то сделал несколько реализаций - и всё. Либо дружить с реализациями, либо соснуть.
                      Ответить
                      • Так ты не забывай, что friend пишется в том классе, который даёт право на доступ. Тот, кого он в друзяшки записал, один хуй не будет лезть в приватные кишки потомков. Он про них, скорее всего, даже ничего не знает. А кишочки зафрендившего ему и через потомков доступны.

                        Так что не вижу смысла в public friend.
                        Ответить
                        • > Тот, кого он в друзяшки записал, один хуй не будет лезть в приватные кишки потомков.
                          Это да, душа потомков - потёмки.

                          Потомки друга хотят лезть в класс (по крайней мере, у меня). Скажем, если смотреть мой пример сверху, компьютер даёт абстрактной программе доступ к памяти, а какая-то конкретная программа работает и пишет.
                          Ответить
                          • > Потомки друга хотят лезть в класс
                            Зачем? Их предок им предоставил недостаточный интерфейс?
                            Ответить
                            • Чтоб не дублировать код. Это же протектед прокси-питушня на ровном месте, а можно было бы обойтись и без неё.
                              Ответить
                              • > Чтоб не дублировать код
                                А так ты связность повышаешь на пустом месте - у тебя хуй знает какое число потомков, написанных хуй знает кем, знает о кишках того класса. В итоге тот класс уже никогда не изменить.
                                Ответить
                                • Вот тут-то и помогла бы возможность давать доступ мелкими кусками. Хотя, проблема Кегдана существует, но её можно сгладить статической толерантностью.
                                  Ответить
                                  • Проблема Кегдана? 0_о
                                    Ответить
                                    • Да. За которую надо платить бы еще более интересным механизмом, чем таблица виртуальных методов, если позволить рассматривать все интерфейсы класса X, унаследованного от формально рассматриваемого Y при передаче по ссылке.
                                      Ответить
                                      • Я только из ООП-диспансера - мне не нужен рецидив. Без меня, парни, без меня...
                                        Ответить
                        • >> один хуй не будет лезть в приватные кишки потомков

                          Больно мне нужно лезть в кишки асов.
                          Ответить
                  • И платили бы еще более интересным механизмом, чем таблица виртуальных методов.

                    да и кто тебе мешает писать кейсы в каждом методе?
                    Ответить
                    • Платили бы на этапе компиляции, а на те случаи, где потребовалась бы динамическая питушня, можно сделать ошибку, предупреждение или просто обрабатывать как объект указанного класса.
                      Ответить
                  • А ещё можно регулярками обмазаться:
                    public *: class Foo
                    {
                        public /^ECMA[script]{6}(\-.+)?$/i: int doSomething(/^Crap.*/(Iterable, ECMAble) foo)
                        {
                            /* Метод доступен классам, название которых попадает под
                               регулярку /^ECMA[script]{6}(\-.+)?$/ (регистронезависимо)
                               и принимает на вход экземпляр класса, который реализует
                               интерфейсы Iterable и ECMAble, и название которого
                               начинается на "Crap" */
                        }
                    }

                    ... и ввести прототипное ООП, что бы прямо в рантайме делать:
                    Foo.prototype./^E.*/ -> int = 42; // Все свойства с названием на "E" становятся типа int и равны 42.
                    Ответить
                    • Да глобальней мыслить надо:
                      compile_time bool access_allowed(const std::string &who) {
                          // arbitrary logic
                      }
                      P.S. Вместо строки лучше что-то более удобное, например тайпинфо.
                      Ответить
                      • Вот это красиво, не городить же шаблоны шаблонов (как я тогда пилил фигню вида combine<'f','1','f','2'>, а wvxvw где-то в глубине души смеялся над крестопроблемами).
                        Ответить
                        • D покури. Там в теории такое можно пильнуть через opDispatch.
                          Ответить
                  • Мне вообще желание делить доступ по классам не понятно. Ситуация в которой класс = единица измерения концептуальных груп в приложении, т.е. таких груп, которые должны знать о своих членах больше чем об остальных, вообще скорее исключение.

                    Как по мне, то лучше отдельные декларации для модулей, и там описывать что доступно снаружи.
                    Ответить
        • в шарпе для этих дел можно засунуть все связанные между собой классы в отдельную сборку,и использовать модификатор видимости internal. Далее копипаст " internal: класс и члены класса с подобным модификатором доступны из любого места кода в той же сборке, однако он недоступен для других программ и сборок (как в случае с модификатором public)."
          Ответить
          • > модификатор видимости internal
            Вот про это я и спрашивал. Спасибо.
            Ответить
        • > Но тогда придётся платить за виртуальные функции.
          В жабе не надо, если число используемых! реализаций не более двух.
          Думаю в других компилерах с JITом хотя бы одна реализация, но инлайнится. Но способ мудацкий и оверхедный в т.ч. по писанине.
          Ответить
        • Паскалоидный путь - классы из одного модуля могут ковырять кишки друг друга.
          Ответить
          • Вот. Одобряю и нахер все эти модификаторы.
            Ответить
            • В go сделали практически как в паскале - все в одном пакете могут дёргать что угодно. И явные экспорты там не нужны - все функции и типы, начинающиеся с большой буквы - публичные, с маленькой - приватные.
              Ну и пакет можно по нескольким файлам размазывать.
              Ответить
    • А если класс не доступен вам? вдруг он internal и с другого неймспейса?
      Или с ActiveX какогото? Я когдато для DsoFramer обьектов что-то подобное писал
      Ответить

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