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

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

Присмотритесь так же к проекту Clay от создателей Orchard CMS. Там то же все элегантно сделано. Вот ссылки с документацией
weblogs.asp.net/bleroy/archive/2010/08/16/clay-malleable-c-dynamic-objects-part-1-why-we-need-it.aspx
weblogs.asp.net/bleroy/archive/2010/08/18/clay-malleable-c-dynamic-objects-part-2.aspx
Ага, спасибо за ссылку. Но Clay позволяет делать вот так IPerson lou = people[0]; за счет использования DynamicProxy от Castle, а он может перехватывать только вызовы виртуальных методов либо методов интерфейса. Т.е. если у меня есть свойство Name и я хочу во вью-модели при сеттере добавить добавить какую-то валидацию на него(которая возможно мне совершенно не нужна или даже вредна в обычной дата-модели), то мне придется сделать свойство виртуальным. Это, конечно, не очень страшно, но мне было интересно сделать решение, которое позволяет не модифицировать сами модельные классы.
ээээх, афтор, вам бы все пять способов сделать и замерить быстродействие! цены бы этой статье не было.

но в целом спасибо!
Честно говоря, основная причина написания статьи — продемонстрировать возможности dynamic type. Но если интересно, то быстродействие я мерил — dynamic выигрывает на создании, ибо кастоловский прокси компилирует объект на лету с emit-апи, но зато потом в моей реализации идут проигрыши на вызове методов реального объекта, поскольку я дергаю их через рефлексию. Впрочем в дата-объекте особо методов быть не должно. Вызов свойств по времени вполне сравним, ибо там я прикрутил вызов через компилируемые лямбда-функции. Что касается решений типа T4 или посташарпа, то там конечно все быстрее, т.к. все нужные действия происходят на компиляции, но зато удобство написания явно ниже(особенно это касается Т4).
sdramare, я бы рекомендовал вам не использовать данный подход в продакшене. Сам часто грешу, используя именно динамики для этой задачи, хоть и в более простой форме чем вы.
Но! Для большо́го количества моделей, с больши́ми уровнями вложенности — заметно тормозит. Лучше сделать свой extension для быстрой генерации ViewModel или взять чужой и переделать под себя. Для себя избрал именно такой способ. :)
Спасибо за ссылку =) Насчет тормозов — я использовал этот подход для построение визуального редактора абстрактного синтаксического дерева некого упрощающего диалекта питона(в нем описывались формулы преобразования одного значения в другое). При общем количестве нод в графе порядка 50 никаких тормозов не видел. Впрочем ничего не берусь утверждать, все зависит от задачи и проекта.
Интересная задача. Даже дважды перечитал формулировку. :-)
Я обычно для прототипов не сложных редакторов или для мелких утилит использую — там скорость работы действительно будет неотличима на глаз от обычного подхода. А вот для большого вложенного N-арного дерева (я пробовал подключить на работающий проект с «рукописными» VM), где каждая вершина с кучей вложенных моделей, тормоза были заметны невооруженным взглядом. Возможно, там хреновая архитектура для динамиков, но, для себя я выводы сделал.
добавь к сеттору файринг нотификации

Капец :) Это ж вроде не перевод…
Опечатку поправил, спасибо. А за «сленг» — извиняюсь, привык за годы. «Добавить к методу установки значения свойства вызов события об изменении значения данного свойства» — так будет лучше?
Я думаю, можно ограничиться "… вызов соответствующего события". Как считаете?
Да, давайте так.
И знаете, в чем крупный и отвратительный недостаток этого подхода? В том, что ваш код перестал быть типизированным. Любые ошибки и опечатки вы отловите уже после компиляции.

При этом вы зачем-то зациклились на прокси, хотя эти задачи прекрасно решаются с помощью обычных объектов и маппинга. А отсюда вырастает целый класс решений по этому поводу, начиная с AutoMapper.
И знаете, в чем крупный и отвратительный недостаток этого подхода? В том, что ваш код перестал быть типизированным. Любые ошибки и опечатки вы отловите уже после компиляции.

Ну во-первых да, знаю, что он перестанет быть типизированным(думаю многие об этом начали догадываться еще прочитав слово dynamic в заголовке). Во-вторых то, что это недостаток, еще очень спорный вопрос. Динамическая типизация имеет как свои плюсы, так и минусы. Посмотрите на тот же питон — на нем прекрасно пишутся приложения, хотя типизация самая что не наесть динамическая. Ну или обжект-си в плане посылки сообщений. Да, ошибки отлавливаются уже после компиляции и по-этому на динамических языках стараются писать через TDD. Впрочем я лично считаю, что и на статике это будет не лишним. Что же касается данного примера, то обратите внимает, что речь идет о довольно простых объект, которые не должны содержать сложную логику, которая сломается. К тому же тем не менее типизацию в каком виде я сохраняю — например если свойство было задано как int, записать в него строку уже не получится.

При этом вы зачем-то зациклились на прокси

Была поставлена задача и предложено решение на основе прокси. Сама задача была взята как база для рассмотрения вопроса о том, как можно использовать новый тип, появившийся в спецификации C# 4.0
эти задачи прекрасно решаются с помощью обычных объектов и маппинга. А отсюда вырастает целый класс решений по этому поводу, начиная с AutoMapper.

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

P.S. Ваш комментарий, на мой взгляд, чрезмерно эмоциональный и несет в себе конфликт-агенты. Мне кажется не стоит продолжать дискуссию в таком тоне, вы не находите?
«К тому же тем не менее типизацию в каком виде я сохраняю — например если свойство было задано как int, записать в него строку уже не получится.»
С точки зрения компилятора — получится.

«Сама задача была взята как база для рассмотрения вопроса о том, как можно использовать новый тип, появившийся в спецификации C# 4.0»
А это как раз типическая ошибка подхода: «у нас есть новая возможность, как ее использовать». В то время как правильнее исходить из «у нас есть такая задача, как ее решить».

«Прекрасно если это так, с удовольствием прочитаю вашу статью об этом.»
habrahabr.ru/search/?q=automapper

«И в вдогонку — когда вы начинаете использовать дататемплейты, стили, триггеры и байдинги в WPF, то очень часто проверка ошибок на этапе компиляции превращается в пыль»
Мир не ограничивается WPF, вот в чем дело. MVVM используется не только там, и задача создания моделей возникает не только там. В вашей статье WPF возникает только в конце, а до этого вы говорите об абстрактном MVVM.
С точки зрения компилятора — получится.

Безусловно. Но в данном случае гарантируется целостность данных — если произойдет некорректный сет вы об этом сразу узнаете.

А это как раз типическая ошибка подхода: «у нас есть новая возможность, как ее использовать». В то время как правильнее исходить из «у нас есть такая задача, как ее решить».

Как известно одна и даже задача, сформулированная в общих терминах имеет множество решений. Выбор нужного делается на основе тех или иных критериев оптимальности. Я уже говорил ранее, динамическая типизация имеет свои плюсы и соответственно предпочтительна для решения определенных классов задач. Вы же почему-то отбрасываете ее в принципе, исходя из тезиса «не компилируется — значит плохо». Вас не смущается, что множество веб-решений, комплексная сложность которых вполне сравнима(а то и превосходит) со сложностью десктоп приложений, делаются на языках с динамической типизацией(причем даже менее строгой, чем та, которой привел я в своей статье)?
habrahabr.ru/search/?q=automapper

Вы сами ходили по этой ссылке? Если да, то в какой из этих статей решается задача «автоматического добавления новых свойств для объектов, возвращаемых методами и функциям»? Мне лично кажется, что не в какой, ибо автомаппер в принципе не предназначен для этого. Кстати говоря, что будет, если в одном из классов, который мы маппим, я поменяю имя свойства? А ничего не будет, все прекрасно скомпилируется. Ошибка будет уже на рантайме.

Мир не ограничивается WPF, вот в чем дело. MVVM используется не только там, и задача создания моделей возникает не только там. В вашей статье WPF возникает только в конце, а до этого вы говорите об абстрактном MVVM.
Я вам просто пример привел. Не нравится WPF — возьмите Silverlight. А в связке (html+css+js), на которой строятся современные веб-интерфейсы, статической типизацией и не пахло. И ничего, никто не умирает.

Я понимаю, если бы вы мне указали на то, что на текущий момент dynamic плохо поддерживается статическими анализаторами кода. Это да, недостаток. А статика сейчас все больше сдает позиции.
«Безусловно. Но в данном случае гарантируется целостность данных — если произойдет некорректный сет вы об этом сразу узнаете.»
Не сразу, а на этапе выполнения.

«вы же почему-то отбрасываете ее в принципе, исходя из тезиса «не компилируется — значит плохо».»
Я ее не отбрасываю. Я просто при прочих равных предпочитаю решения, которые компилируются (пусть даже они требуют, скажем, кодогенератора).

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

«Не нравится WPF — возьмите Silverlight.»
… и замлом мир тоже не ограничивается, в общем-то.

«на текущий момент dynamic плохо поддерживается статическими анализаторами кода»
Проблема в том, что его вообще очень сложно поддержать анализаторами кода, потому что public void Process(dynamic smth) может быть вызван откуда угодно, и в динамике может быть что угодно. Прощай, анализ. Именно поэтому я предпочту кодогенерацию или типизованный прокси (хоть на рефлекшне) динамику.

«А в связке (html+css+js), на которой строятся современные веб-интерфейсы, статической типизацией и не пахло.»
И знаете, как это усложняет разработку? По сравнению с нормальным типизованным asp.net mvc?
И в вдогонку — когда вы начинаете использовать дататемплейты, стили, триггеры и байдинги в WPF, то очень часто проверка ошибок на этапе компиляции превращается в пыль. Вы никогда не сталкивались с ситуацией, когда байдинг на какой-нибудь прекрасно скомпилированной странице/контроле не работает, т.к. не правильно заданно имя свойства или в датаконтексте по воли злого рока оказался объект не того типа, которого вы ожидали? Является наличие таких особенностей при построении UI через хaml и WPF поводом отказаться от их использования?
Статическая типизация это вообще спорная вещь, сама по себе много не дает, зато ее отсутствие подталкивает к написанию модульных тестов, TDD и т.п. Тем более, вы эту типизацию затем все равно теряете в xaml.

Насколько я понимаю, автор как раз хотел избежать рутинной работы по созданию таких объектов, большинство которых скорее всего ничем 'интеллектуальным' заниматься не будут, кроме как оборачивать и пробрасывать вызовы, что по сути и есть проксирование.
Ваш подход мне совсем непонятен. Зачем создавать кучу view models, которые еще и никак не будут связаны с моделью, кроме как логически, да еще и маппинги прописывать? И да, я бы тогда уж с EmitMapper начинал.

На мой взгляд вариантом тут может являться применение шаблона для генерации делегирующего свойства с оповещением нотификации, если говорить о INotifyPropertyChanged. Если говорить о добавочных свойствах, то я думаю, что свойства в студии генерируются проще, чем при подходе автора. А вот с оборачиванием внутренних объектов во view models придется возиться.
«Статическая типизация это вообще спорная вещь»
Для кого как.

«ее отсутствие подталкивает к написанию модульных тестов, TDD и т.п.»
А ее наличие — к выявлению части ошибок еще на этапе компиляции, экономя мне минуты при сборке.

«Тем более, вы эту типизацию затем все равно теряете в xaml.»
Замлом жизнь MVVM не ограничивается.

«Зачем создавать кучу view models, которые еще и никак не будут связаны с моделью, кроме как логически, да еще и маппинги прописывать?»
Чтобы получить чистую view model, не дающую побочных эффектов на бизнес-объект, ее породивший.
«Для кого как.»
На мой взгляд существенным преимуществом статической является упрощение статического анализа, иначе с этим возникают серьезные проблемы. А так по опыту могу сказать, что у многих статическая создает ложное чувство корректности программы, в то время как контролирует только часть ошибок, и то глупых. Впрочем на эту тему уже столько сказано и написано, что статическая типизация это все же безусловно спорная вещь.

«А ее наличие — к выявлению части ошибок еще на этапе компиляции, экономя мне минуты при сборке.»
Либо вы работаете над гигантскими проектами и я вам завидую, либо существует проблема запутанности зависимостей, возможно архитектуры. Опять же по опыту могу сказать, что программисты как правило нажимают в студии кнопочку Build и компилятор начинает молотить до победного конца. Если подходить по уму, то в случае с модульными тестами у вас возникнает 'пролема' создания более продуманной структуры зависимостей, что в конечном счете позволяет минимизировать выигрышь обрывания процесса компиляции при обнаружении первой ошибки.

«Тем более, вы эту типизацию затем все равно теряете в xaml.»
Ок, может быть вы его прикрутили куда-то еще. Но MVVM в первую очередь относится к Microsoft, WPF, Silverlight, XAML.

«Чтобы получить чистую view model, не дающую побочных эффектов на бизнес-объект, ее породивший.»
Вы имели в виду объект, который оборачивает View model, а не порождает?
По паттерну view model никак не может аффектить бизнес-объекты. Зато по тому же паттерну View model занимается связыванием model и view, по сути он содержит в себе бизнес-объекты и обеспечивает работу с ними. Подмена модели другими объектами, не связанными с моделью выглядит странно.
«Либо вы работаете над гигантскими проектами»
Достаточно большим, чтобы компиляция шла долго. Обрыв ее на ранней стадии полезен.

«Но MVVM в первую очередь относится к Microsoft, WPF, Silverlight, XAML.»
Он немножко старше.

«Вы имели в виду объект, который оборачивает View model, а не порождает?»
Я имею в виду именно порождает. Я просто не считаю, что изменения в viewmodel должны всегда сразу идти в связанную domain model.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории