Как стать автором
Обновить

Комментарии 31

Как вариант — АОП.
Я его имел ввиду под «сторонние средства», т.к. вручную добавлять АОП без модификации исходных классов — дело не благодарное.
Да, я в курсе и про интеграцию с COM и про делегаты. В коде я постарался сделать акцент на бизнес-логике и спрятать служебный код. Можно смотреть на это как на «почти АОП».
У динамиков «четкое» применение в любом месте, где от этого есть бенефит, а для не какой-то конкретной технологии.
У динамиков куча применений. Я периодически использую, как прокси к моделям. Как-то так:
    public class DynamicViewModel : DynamicObject, INotifyPropertyChanged
    {
        /*...*/


        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            string propertyName = binder.Name;
            PropertyInfo property = _model.GetType().GetProperty(propertyName);

            if (property == null || property.CanRead == false)
            {
                result = null;
                return false;
            }

            result = property.GetValue(_model, null);
            return true;
        }


        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            string propertyName = binder.Name;
            PropertyInfo property = _model.GetType().GetProperty(propertyName);

            if (property == null || property.CanWrite == false)
                return false;

            property.SetValue(_model, value, null);

            OnPropertyChanged(propertyName);
            return true;
        }
    }


Надо только помнить, что оно не очень-то шустро…
Упс, написал в попыхах, но я думаю все догадались, что там:

    public class DynamicViewModel<T> : DynamicObject, INotifyPropertyChanged
    {
        private T _model;
Спасибо. Я обычно такое делаю через аспекты, поэтому ваше решение всё больше меня склоняет к выводу, что dynamic полезен в плане «почти АОП».
Вы, кажется, сделали в точности то, что предлагает фреймворк LinFu в разделе DuckTyping, но тут более конкретно, а там — более общо. Думается, вам будет интересно посмотреть www.codeproject.com/KB/cs/LinFuPart2.aspx (в том числе и на другие статьи этой же серии)
Смотрел на LinFu в контексте NHibernate, но про LinFu и DynamicObject раньше не слышал, спасибо.
при названии статьи «Измеряем производительность ...» хотелось бы видеть таблички с замерами
а уж если даете ссылки на «похожий подход», то и сравнения подходов
при названии статьи «Измеряем производительность ...» хотелось бы видеть таблички с замерами

Замерами Thread.Sleep(TimeSpan.FromSeconds(rand.Next(5)));? Это действительно интересно?
а уж если даете ссылки на «похожий подход», то и сравнения подходов

Дело в том, что это практически «такой же подход», так что сравнивать можно только названия.
я дико извиняюсь )
понял о чем статья, только когда прочел код
поначалу подумалось, что замеряем производительность DLR по отношению к Static(?)LR
после дошло, что замеряем любой код с помощью DLR (как и указано в названии)
Пост на который ссылается автор я писал учень давно, и к тому времени отношение к АОП, по крайней мере, очень сильно изменилось. В частности PostSharp я уже перестал использовать. Конечно, у него есть свои use cases, но практика показывает, что PostSharp не может адекватно (без гигантского кол-ва телодвижений или ручного переписывания IL) влиять на существующие структуры. То есть, он может например обернуть существующий код в TransactionScope или например засунуть все вызовы в Task.Factory.StartNew(), но на практике когда вы начинаете действительно “мешать” аспекты (например, многопооточность+транзакции+stream processing), никакой PostSharp не даст вам возможность декларативно правильно и быстро описать взаимодействие компонент – уровень гранулярности совсем не тот.

На практике, у меня получается использовать 3 механизма:

  • Для очень простых и ограниченных задач, например когда нужно получить в отсутствии variadic templates набор типов или методов с произвольным количеством аргументов, я использую Т4.
  • Для более сложных задач, например когда нужно на основе существующих структур данных наплодить еще данных, я использую транскомпиляцию. Наверное о ней нужен отдельный пост, но суть в том, что я использую механизмы метапрограммирования Boo, компилирую программу, потом декомпилирую ее в C# и вставляю в мои C#-ные проекты. Данный подход реализован отдельным расширением Visual Studio.
  • Ну и наконец для безумно сложных задач связанных, например, с многопоточным управлением иерархических конечных автоматов, я использую DSLи.

А пример кода в статье мне нравится – мне кажется что по сути дела можно попробовать как-то контролировать эту “динамическую подмену” в IoC-контейнере и тем самым профилировать определенные участки кода. (Хотя профиляторы тоже никто не отменял.)
А пример кода в статье мне нравится – мне кажется что по сути дела можно попробовать как-то контролировать эту “динамическую подмену” в IoC-контейнере и тем самым профилировать определенные участки кода. (Хотя профиляторы тоже никто не отменял.)

Мысль конечно интересная, но думаю, что без прокси, прозрачная «динамическая подмена» вряд ли возможна. Хотя может в каком-нибудь LinFu уже есть решение.
Моя вторая статья очень перекликалась с субжем: habrahabr.ru/blogs/net/103558/ — там я тоже сравнивал скорость работы динамиков.
Тут не про скорость работы динамиков, а про использование динамиков в качестве прозрачной прокси для измерения производительности кода.
Как бы скорость работы динамиков тоже влияет на результат замера. И очень бы не плохо знать сколько именно добавляет использование динамиков, что я и делал в своей статье.

Я под «перекликались» именно в этом ракурсе имел ввиду.
В топике я постарался минимизировать влияние динамического типа данных и измеряю скорость только в момент непосредственного вызова метода.
Для таких вещей есть DynamicProxy От Castle'a
Кстати если вызывать методы не через ревлекшн а через экспрешны будет значительно быстрее. DynamicProxy так и делает
Для таких вещей есть DynamicProxy От Castle'a

Ещё есть LinFu, PostSharp, Unity.Interception и т.д. Все они попадают под определение «сторонних средств», в топике я написал, что не отказался от их использования целенаправленно.
Кстати если вызывать методы не через ревлекшн а через экспрешны будет значительно быстрее.

Да я знаю, ещё быстрее сформировать делегат через Delegate.CreateDelegate, но, думаю, это не критично для не production кода.
*отказался)
У вашего кода есть крупный недостаток: он не type-safe. Для обертки вокруг reflection это оправданно, для обертки вокруг класса с известным во время компиляции публичным интерфейсом — нет.

Такие вещи «традиционно» делаются через динамические прокси.
У вашего кода есть крупный недостаток: он не type-safe.

Не вижу в этом крупного недостатка для проверочного кода.
Для обертки вокруг reflection это оправданно, для обертки вокруг класса с известным во время компиляции публичным интерфейсом — нет.

К чему относиться, описанный динамический класс?
Такие вещи «традиционно» делаются через «динамические прокси».

Отвечал уже не раз, но повторюсь:
  1. В языке нет встроенных средств, чтобы быстро и легко решить эту задачу через динамические прокси;
  2. «Прибегать к помощи сторонних средств я не хотел», т.к. задача не настолько сложна и магия в runtime мне не нужна;
  3. Динамические прокси успешно использую в production, цель была не в использование прозрачной замены (например, достаточно попробовать передать wrapper в метод принимающий объект исходного типа, чтобы понять недостаток предложенного подхода).
«Не вижу в этом крупного недостатка для проверочного кода.»
Подобного рода «проверочный код» (проверка производительности при реальном использовании объекта; если бы вам не надо было реальное использование, вы бы написали тест) регулярно просачивается в продакшн-код.

Собственно, весь смысл враппера в том, чтобы не знать, что мы вызываем.

«К чему относиться, описанный динамический класс?»
Ко второму, очевидно. Вы же знаете интерфейс класса, который используете.

«В языке нет встроенных средств, чтобы быстро и легко решить эту задачу через динамические прокси;»
Вы свою задачу тоже решаете не встроенными средствами языка, а через Reflection, который встроенное средство платформы.

"«Прибегать к помощи сторонних средств я не хотел», т.к. задача не настолько сложна и магия в runtime мне не нужна;"
При чем тут сторонние средства?

«цель была не в использование прозрачной замены»
А в чем была цель? Если вы хотели получить тестовый код, то он у вас слишком хрупкий.
Подобного рода «проверочный код» регулярно просачивается в продакшн-код.

В production коде я пользуюсь профайлером.
если бы вам не надо было реальное использование, вы бы написали тест

Я и написал тест для себя, но с удобной мне обёрткой.
Собственно, весь смысл враппера в том, чтобы не знать, что мы вызываем.

Смысл враппера (он же адаптер и обёртка) в том, чтобы адаптировать интерфейс объекта к требованиям системы. А вот смысл прокси как раз служить прозрачной заменой.
Ко второму, очевидно. Вы же знаете интерфейс класса, который используете.

Да, но к динамическому типу данных я могу добавить любые поля, методы и т.д. и узнать об ошибке только в runtime. Даже в Visual Studio я пишу «наугад». Так что, скорее всё-таки первое.
Вы свою задачу тоже решаете не встроенными средствами языка, а через Reflection, который встроенное средство платформы.

Говоря язык, я подразумевал платформу, т.к. в языке нет даже средств вывода и обсуждать его отдельно нет смысла. Уверен вы поняли меня сразу или в платформе есть средства для быстрого и легкого создания «динамических прокси»?
При чем тут сторонние средства?

Думаю из предыдущего вопроса понятно причём.
А в чем была цель? Если вы хотели получить тестовый код, то он у вас слишком хрупкий.

Javascript тоже очень хрупкий, хотя mainstream. Недостаток надёжности (который свойственен любой динамике), компенсируется удобством использования и прозрачностью кода тестов.
«Да, но к динамическому типу данных я могу добавить любые поля, методы и т.д. и узнать об ошибке только в runtime. Даже в Visual Studio я пишу «наугад». Так что, скорее всё-таки первое.»
Один из нас не понимает другого. Недостаток вашего кода именно в том, что все ваши ошибки будут в runtime.

«Javascript тоже очень хрупкий, хотя mainstream.»
Он мейнстрим там, где нет менее хрупких средств. И даже там его всячески пытаются сделать менее хрупким, jslint тому свидетельство.

«Недостаток надёжности (который свойственен любой динамике), компенсируется удобством использования и прозрачностью кода тестов. „
С точки зрения кода тестов PerformanceProxy.Create{Of T}(instance) ничем не хуже вашего решения, но при этом еще и дает (должен дать) статическую типизацию. То, что при этом под капотом PerformanceProxy десять MLoC вашего пропьетарного кода или полтора вызова к третьесторонней библиотеке — никого не волнует.
Недостаток вашего кода именно в том, что все ваши ошибки будут в runtime.

Да это недостаток, я этого не отрицаю. Я просто хотел донести мысль, что на другой чаше весов «удобством использования и прозрачность кода тестов».
Он мейнстрим там, где нет менее хрупких средств. И даже там его всячески пытаются сделать менее хрупким, jslint тому свидетельство.

Думаю, если бы его хрупкость не была следствием гибкости, то его давно бы заменили. А так вон NodeJS активно развивается, хотя альтернатив уже очень много. JSLint только указывает на потенциальные ошибки, такой статический анализ полезен даже не для хрупкого C# (не зря в VS это отдельный инструмент).
С точки зрения кода тестов PerformanceProxy.Create{Of T}(instance) ничем не хуже вашего решения, но при этом еще и дает (должен дать) статическую типизацию.

Это отличное решение! Более того, оно позволит мне измерить производительность в методах, куда я не могу передать свою динамическую обёртку. Я всего лишь предложил альтернативное, ограниченное решение без использования сторонних средств (или PerformanceProxy где-то в недрах платформы?)
«Я просто хотел донести мысль, что на другой чаше весов «удобством использования и прозрачность кода тестов».»
Я уже привел пример того, как сделать не менее удобно и прозрачно (для теста, подчеркиваю).

«Думаю, если бы его хрупкость не была следствием гибкости, то его давно бы заменили.»
Очень сложно заменить технологию, которая уже используется в миллионах мест.

«Я всего лишь предложил альтернативное, ограниченное решение без использования сторонних средств (или PerformanceProxy где-то в недрах платформы?) „
За что вы так не любите сторонние средства?
За что вы так не любите сторонние средства?

За то, что мне нужно их искать, скачивать, разбираться с их API вместо того, чтобы решать бизнес-цели, надеятся на то, что они не криво написаны, модифицировать рабочий код для них (например, вешать атрибуты или помечать члены как virtual)? Я предпочитаю выбирать инструмент под задачу и, если задача требует сторонних средств, я ими воспользуюсь. К счастью, моя задача решилась в рамках платформы.
«За то, что мне нужно их искать, скачивать, разбираться с их API вместо того, чтобы решать бизнес-цели, надеятся на то, что они не криво написаны, модифицировать рабочий код для них (например, вешать атрибуты или помечать члены как virtual)? „
Ну так вы выбирайте те средства, проблемы от которых минимальны.

“К счастью, моя задача решилась в рамках платформы. „
Я просто указываю вам на (для меня — фундаментальный) недостаток вашего решения.

(я просто слишком много раз разбирал ошибки, возникающие из-за слабой типизации)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории