Как стать автором
Обновить
11
0
Сергей Аликин @Alser

Пользователь

Отправить сообщение

В примере ForArray массив находится в филде, поэтому JIT не может быть уверен, что он не изменится на полностью другой массив, и не удаляет boundary check.

Если массив записать в локальную переменную, и далее по ней идти в цикле до Length, то boundary check удаляется. Код цикла for идентичен варианту foreach на .NET 7 (только регистры разные).

    public int M2()
    {
        var arr = array;
        var sum = 0;
        for (var i = 0; i < arr.Length; i++)
        {
            sum += arr[i];
        }
        return sum;
    }
G_M28255_IG03:
       mov      ecx, esi
       add      edi, dword ptr [rax+4*rcx+10H]
       inc      esi
       cmp      edx, esi
       jg       SHORT G_M28255_IG03

В .NET 6 для for IL такой же, а для foreach одна инструкция add заменяется на две mov+add

G_M55486_IG03:
       movsxd   rcx, esi
       mov      ecx, dword ptr [rdi+4*rcx+16]
       add      eax, ecx
       inc      esi
       cmp      edx, esi
       jg       SHORT G_M55486_IG03

Подробнее в Compiler Explorer https://godbolt.org/z/MdEfGeT1E

Понял вашу позицию, да, это компоновщик + нечто еще. То, как просто реализовать компоновщик, описано в любой книжке по паттернам, начиная с GoF. Реализовывать компоновщик всегда ТАК я никому бы не посоветовал, это излишне сложно, а цель проектирования — борьба со сложностью.
Объясню иначе. Все, что я сделал — взял паттерн компоновщик и применил к нему другие паттерны (ну и адаптировал к реалиям C#). Это усложняет структуру, но дает больше гибкости. Получить не-компоновщик при этом я не мог.
Из GoF. «Паттерн Composite. Назначение: компонует объекты в древовидные структуры для представления иерархий часть-целое. Позволяет клиентам единообразно трактовать индивидуальные и составные объекты… Ключом к паттерну компоновщик является абстрактный класс, который представляет одновременно и примитивы, и контейнеры».

Для того, что я изложил в посте, верны все 3 утверждения, так что это компоновщик. Нужно ли писать весь мой код, чтобы реализовать компоновщик? Нет, совсем не нужно. Во многих случаях этот код избыточен. В чем смысл написанного мной кода? В том, что написали его 1 раз (имею ввиду IComponent, итераторы и NullObject-коллекции) и в дальнейшем используете его, реализуя конкретную функциональность в каждом конкретном случае свою (и для структуры, и для бизнес-логики вы реализуете свое в каждой иерархии IMenuItem!)

В чем преимущества предложенного мною подхода: для множества схожих задач можно выделить общий интерфейс иерархии и реализовать NullObject-коллекцию для него 1 раз. Плюс вы получаете некоторый готовый функционал (итераторы) через методы-расширения. Этот мой подход довольно банален и ничего нового и выдающегося из себя не представляет.
Если я правильно понял, то я об этом вскользь упомянул: инкапсулировать List в отдельный класс, который реализовывал бы ICollection и делегировал вызовы в List. Да, тогда структура и логика полностью отделены.
Не понимаю, почему? Свойства и поведения дочерних элементов по-прежнему протягиваются до компоновщика, как вы и написали, просто это реализуется в том же классе для бизнес-логики (Display, Name) и в отдельном классе для структуры (Add, Remove). Классы объединяются через композицию, но объединение происходит уже в композитном классе Menu. Я в примере использовал стандартный List и как бы автоматически получил реализацию интерфейса структуры. А вы попробуйте передать свой класс TChildrenCollection, реализующий Add, Remove и GetChild, функциональность будет 1-в-1 по GoF.
Так вы и работаете с деревом как с элементом, вызываете Display для элемента — выводится дерево, этот аспект компоновщика я не изменял. IComponent введен для того, чтобы частично вынести код из IMenuItem и других реализаций в некоторую общую мини-библиотеку, которая не будет изменяться для различных иерархий. Вас возможно смутил метод GetDescendants(), он позволяет работать с элементом, думая, что он дерево, но это лишь дополнительная функциональность, которая автоматически реализуется для любого наследника IComponent.
Да, правильно. А я вроде так и сделал: неизменяемая синглтон-коллекция, получаемая через свойство ComponentCollections.EmptyCollection. Эксепшены кидаются только при попытке изменить коллекцию (вызвать Add, Remove, Clear и т.п.) Если вы обращаетесь к Count или GetEnumerator, то с Leaf все работает так же, как и с Composite-объектами.
Долго думал, с чем из сказанного вы не согласились, скорее всего с фразой «такие же опытные программисты, как и вы». Да, пожалуй даже студент 2 курса сможет воспользоваться вашим ПО для оптимизации кода, если он при этом знает C# и АОП, и это хорошо.
Но моя мысль была в другом, попытаюсь максимально четко сформулировать: «если пишешь ПО в одиночку и для души, то делай его открытым, не сомневайся и не жалей». И это независимо от порога вхождения потенциальных клиентов. Для меня эта мысль была не очевидной до некоторых пор, и мне показалось, что у вас была похожая ситуация. Я даже обращался к нескольким немаленьким компаниям с вопросами о реализации проекта, лишь тогда понял, как на отечественном рынке ПО все печально в плане таких вот «продуктов для программистов», в отличие от «продуктов для бизнеса».
Это безусловно так, и подобных возможностей в C# ох как не хватает. Но кто в конечном счете будет потребителем вашего продукта — такие же опытные программисты, как и вы, да крупные компании, которым надо еще суметь втолковать преимущества конкретно вашего решения перед конкурентами (слово презентабельность неверно отражало суть, да).

Я имел ввиду, что идея монетизации изначально была недееспособна. И я поначалу себя точно также обманывал, наступил на те же грабли (в двух словах пишу фреймворк для упрощения разработки и интеграции экспертных систем с кодом программы, которая не нужна никому, кроме людей, знакомых с основами ИИ). Проще было написать несколько мелких игрушек под мобильные платформы и сразу получить валютный фидбек, но Идея не давала спать по ночам.
Вот читал как будто бы про свой проект и мое к нему отношение, автор как в душу глядел… И про периодические кризисы в творчестве верно подмечено. Но для меня стимулом возобновлять и продолжать работу является участие в конференциях и возможность показать проект хоть кому-то, стимул «монетизации» довольно быстро угас, а явных конкурентов не нашел (плохо искал наверно).

Правда пока не готов красивый интерфейс показывать нечего кроме абстрактных схем, а интерфейс выполняется в последнюю очередь (конечно есть всякие сендвич интеграции, но они не всегда работают). В случае библиотеки по типу PostSharp с презентабельностью наверное еще хуже, как сказал один знакомый опытный разработчик «это все хайтек в чистом виде, а он в России не интересен почти никому».
У новичка в Gtk (в лице меня) возникло желание повторить все написанное.
Правильно, но тут даже если мы перехватим все исключения — ничего путного не выйдет :)
Очистка объектов с финализаторами производится за 2 сборки мусора, поэтому у объекта больше шансов попасть во 2-е поколение, которое собирается реже. GC может работать в несколько потоков (как например при фоновой сборке в .net 4, когда объекты поколений 0-1 и 2 собираются в разных потоках), поэтому Listener != null не спасет, надо ставить мьютекс, что опять же чревато (к управляемым ссылками тут обращаться вообще не стоит). Наконец объект TcpListener имеет свой финализатор, т.е. этот наш ~Server не делает ровным счетом ничего, кроме как создает проблемы :)
О финализаторах лучше забыть как о страшном сне до тех пор, пока не понадобится работать с неуправляемыми ресурсами. А сама статья неплохая, про основы сокетов и потоков :)
Как-то финализатор класса Server нелепо смотрится. Здесь разумнее реализовать IDisposable, а TcpListener должен сам остановиться, когда его GC найдет.

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Зарегистрирован
Активность