Предупреждение: Нижеследующее многие сочтут извращением с C#. Возможно конечно это и не так, но я Вас предупредил:).
В Ruby есть интересная особенность для перехвата вызовов несуществующих методов. В таких случаях Ruby вызывает метод вашего класса с названием «method_missing». Автор этого текста показывал пример этого на IronRuby в другой статье.
Для динамических языков это может быть нормой, но в статически типизированных языках такого не бывает.
Не было до текущего момента!(Барабанная дробь)
В C# 4.0 вводится новое ключевое слово dynamic, которое добавляет динамические свойства к статически типизированному языку. Не бойтесь, никто не заставит вас это использовать(кроме автора этой статьи). На самом деле, оригинальная цель этого — сделать interop с COM намного проще. Но это не тема этой статьи, посмотрим как можно повеселиться с этой фичей:)
Автор решил попытаться реализовать нечто вроде method_missing.
Первое что он написал — это простейший динамический словарь который использует свойства для добавления и получения значений в/из словаря используя имя свойства как ключ. Вот пример использования:
Это не так уж плохо выглядет, и код простой. Чтобы сделать динамический объект, у нас есть выбор или реализовать интерфейс IDynamicMetaObjectProvider или просто наследоваться от DynamicObject. Автор выбрал второй подход потому что это быстрее и проще сделать. Вот код:
Всё что автор здесь делает — перегружает метод TrySetMember который вызывается при попытке установить свойство динамического объекта.Автор берет имя поля и использует его как ключ словаря. Так же автор мерегружает метод TryGetMember чтобы возвращать значения из словаря.
Стоит отметить, в Ruby на самом деле нету свойств и методов. Всё является методом, надо только позаботиться о method_missing. Не существует field_missing метода, например. В C# есть разница, поэтому есть другой метод который мы можем перегрузить — TryInvokeMember чтобы обрабатывать динамические вызовы.
Какой хаос можно создать с помощью этого в MVC?
Т.к. автор любитель явно типизированного view data в ASP.NET MVC, он любит вставлять некоторые вспомогательные данные в ViewDataDictionary. Конечно это добавляет синтаксический оверхед, который он любит уменьшать. Вот что было:
Похоже сюда можно впихнуть динамический словарь.
Прежде чем показывать код, сначала покажу результат. Автор создал новое свойство для Controller и ViewPage с названием Data (вместо ViewData), просто чтобы было покороче и изза нежелания называть его VD.
Вот код контроллера:
Заметьте что Message и Body на самом деле не свойства Data, это ключи словаря. Эта запись эквивалетна ViewData[«Message»] = "…".
В этом представлении автор создал собственные правила где все доступ к данным будут закодированы html (Html.Encode, хз как это более адекватно перевести) если не использовать знак подчеркивания.
Имейте ввиду что Data.Message здесь эквивалентна ViewData[«Message»].
Вот скриншот конечного результата:

Вот как автор это сделал. Сначала был создан класс DynamicViewData:
Если приглядеться, вы заметите что автор делает некие махинации в TryGetMember. Это то, где он проверяет на наличие знака подчеркивания перед именем свойства, и в случае наличия — кодирует текст как html (Естественно знак подчеркивания при этом из названия ключа для словаря убирается).
Дальше автор создает собственный DynamicController:
и DynamicViewPage (оба из которых используют новый класс DynamicViewData):
В папке Views автор обновил web.config чтобы сделать DynamicViewPage базовым классом по умолчанию для представлений вместо ViewPage. Это можно изменить устанавливая аттрибут pageBaseType элемента .
Автор надеется что это было весело, и прекрасно осознает, что хоть некоторые и будут ругаться за такое использование кейворда dynamic, другие могут увидеть потенциал в этой новой фишки.
В Ruby есть интересная особенность для перехвата вызовов несуществующих методов. В таких случаях Ruby вызывает метод вашего класса с названием «method_missing». Автор этого текста показывал пример этого на IronRuby в другой статье.
Для динамических языков это может быть нормой, но в статически типизированных языках такого не бывает.
Не было до текущего момента!(Барабанная дробь)
В C# 4.0 вводится новое ключевое слово dynamic, которое добавляет динамические свойства к статически типизированному языку. Не бойтесь, никто не заставит вас это использовать(кроме автора этой статьи). На самом деле, оригинальная цель этого — сделать interop с COM намного проще. Но это не тема этой статьи, посмотрим как можно повеселиться с этой фичей:)
Автор решил попытаться реализовать нечто вроде method_missing.
Первое что он написал — это простейший динамический словарь который использует свойства для добавления и получения значений в/из словаря используя имя свойства как ключ. Вот пример использования:
- static void Main(string[] args)
- {
- dynamic dict = new DynamicDictionary();
- dict.Foo = "Some Value"; // Compare to dict["Foo"] = "Some Value";
- dict.Bar = 123; // Compare to dict["Bar"] = 123;
- Console.WriteLine("Foo: {0}, Bar: {1}", dict.Foo, dict.Bar);
- Console.ReadLine();
- }
-
* This source code was highlighted with Source Code Highlighter.Это не так уж плохо выглядет, и код простой. Чтобы сделать динамический объект, у нас есть выбор или реализовать интерфейс IDynamicMetaObjectProvider или просто наследоваться от DynamicObject. Автор выбрал второй подход потому что это быстрее и проще сделать. Вот код:
-
-
- public class DynamicDictionary : DynamicObject
- {
- Dictionary<string, object>
- _dictionary = new Dictionary<string, object>();
- public override bool TrySetMember(SetMemberBinder binder, object value)
- {
- _dictionary[binder.Name] = value;
- return true;
- }
- public override bool TryGetMember(GetMemberBinder binder,
- out object result)
- {
- return _dictionary.TryGetValue(binder.Name, out result);
- }
- }
-
-
* This source code was highlighted with Source Code Highlighter.Всё что автор здесь делает — перегружает метод TrySetMember который вызывается при попытке установить свойство динамического объекта.Автор берет имя поля и использует его как ключ словаря. Так же автор мерегружает метод TryGetMember чтобы возвращать значения из словаря.
Стоит отметить, в Ruby на самом деле нету свойств и методов. Всё является методом, надо только позаботиться о method_missing. Не существует field_missing метода, например. В C# есть разница, поэтому есть другой метод который мы можем перегрузить — TryInvokeMember чтобы обрабатывать динамические вызовы.
Какой хаос можно создать с помощью этого в MVC?
Т.к. автор любитель явно типизированного view data в ASP.NET MVC, он любит вставлять некоторые вспомогательные данные в ViewDataDictionary. Конечно это добавляет синтаксический оверхед, который он любит уменьшать. Вот что было:
- // store in ViewData
- ViewData["Message"] = "Hello World";
-
- // pull out of view data
- <%= Html.Encode(ViewData["Message"]) %>
* This source code was highlighted with Source Code Highlighter.Похоже сюда можно впихнуть динамический словарь.
Прежде чем показывать код, сначала покажу результат. Автор создал новое свойство для Controller и ViewPage с названием Data (вместо ViewData), просто чтобы было покороче и изза нежелания называть его VD.
Вот код контроллера:
- public ActionResult Index() {
- Data.Message = "<cool>Welcome to ASP.NET MVC!</cool> (encoded)";
- Data.Body = "<strong>This is not encoded</strong>.";
-
- return View();
- }
* This source code was highlighted with Source Code Highlighter.Заметьте что Message и Body на самом деле не свойства Data, это ключи словаря. Эта запись эквивалетна ViewData[«Message»] = "…".
В этом представлении автор создал собственные правила где все доступ к данным будут закодированы html (Html.Encode, хз как это более адекватно перевести) если не использовать знак подчеркивания.
- <asp:Content ContentPlaceHolderID="MainContent" runat="server">
- <h2><%= Data.Message %></h2>
- <p>
- <%= Data._Body %>
- </p>
- </asp:Content>
* This source code was highlighted with Source Code Highlighter.Имейте ввиду что Data.Message здесь эквивалентна ViewData[«Message»].
Вот скриншот конечного результата:

Вот как автор это сделал. Сначала был создан класс DynamicViewData:
- public class DynamicViewData : DynamicObject {
- public DynamicViewData(ViewDataDictionary viewData) {
- _viewData = viewData;
- }
- private ViewDataDictionary _viewData;
-
- public override bool TrySetMember(SetMemberBinder binder, object value) {
- _viewData[binder.Name] = value;
- return true;
- }
-
- public override bool TryGetMember(GetMemberBinder binder,
- out object result) {
- string key = binder.Name;
- bool encoded = true;
- if (key.StartsWith("_")) {
- key = key.Substring(1);
- encoded = false;
- }
- result = _viewData.Eval(key);
- if (encoded) {
- result = System.Web.HttpUtility.HtmlEncode(result.ToString());
- }
- return true;
- }
- }
* This source code was highlighted with Source Code Highlighter.Если приглядеться, вы заметите что автор делает некие махинации в TryGetMember. Это то, где он проверяет на наличие знака подчеркивания перед именем свойства, и в случае наличия — кодирует текст как html (Естественно знак подчеркивания при этом из названия ключа для словаря убирается).
Дальше автор создает собственный DynamicController:
- public class DynamicController : Controller {
- public dynamic Data {
- get {
- _viewData = _viewData ?? new DynamicViewData(ViewData);
- return _viewData;
- }
- }
- dynamic _viewData = null;
- }
* This source code was highlighted with Source Code Highlighter.и DynamicViewPage (оба из которых используют новый класс DynamicViewData):
- public class DynamicViewPage : ViewPage {
- public dynamic Data {
- get {
- _viewData = _viewData ?? new DynamicViewData(ViewData);
- return _viewData;
- }
- }
- dynamic _viewData = null;
- }
* This source code was highlighted with Source Code Highlighter.В папке Views автор обновил web.config чтобы сделать DynamicViewPage базовым классом по умолчанию для представлений вместо ViewPage. Это можно изменить устанавливая аттрибут pageBaseType элемента .
Автор надеется что это было весело, и прекрасно осознает, что хоть некоторые и будут ругаться за такое использование кейворда dynamic, другие могут увидеть потенциал в этой новой фишки.
