Dynamic Language Runtime
98C# --- Сборки .NET --- Dynamic Language Runtime
Теперь, когда прояснилась суть "динамических данных", давайте исследуем, как они обрабатываются. В версии .NET 4.0 общеязыковая исполняющая среда (Common Language Runtime — CLR) получила дополняющую среду времени выполнения, которая называется исполняющей средой динамического языка (Dynamic Language Runtime — DLR). Концепция "динамической исполняющей среды" определенно не нова. На самом деле ее много лет используют такие языки программирования, как Smalltalk, LISP, Ruby и Python. В основе своей динамическая исполняющая среда предоставляет динамическим языкам возможность обнаруживать типы целиком во время выполнения, без каких-либо проверок при компиляции.
При наличии опыта работы со строго типизированными языками (включая C# без динамических типов), может показаться нежелательным само понятие такой исполняющей среды. В конце концов, обычно, когда только возможно, лучше получать ошибки во время компиляции, а не во время выполнения. Тем не менее, динамические языки и исполняющие среды предлагают ряд интересных возможностей, включая перечисленные ниже:
Исключительно гибкая кодовая база. Можно изменять код, не внося многочисленных модификаций в типы данных.
Очень простой способ взаимодействия с разнообразными типами объектов, построенными на разных платформах и языках программирования.
Способ добавления или удаления членов типа в памяти во время выполнения.
Роль DLR состоит в том, чтобы позволить различным динамическим языка работать с исполняющей средой .NET и предоставлять им возможность взаимодействия с другим кодом .NET. Два популярных динамических языка, которые используют DLR — это IronPython и IronRuby. Эти языки живут в "динамической вселенной", где типы определяются исключительно во время выполнения. К тому же эти языки имеют доступ ко всему богатству библиотек базовых классов .NET. Еще лучше то, что их кодовая база может взаимодействовать с C# (и наоборот), благодаря включению ключевого слова dynamic.
Роль деревьев выражений
Среда DLR использует деревья выражений для описания динамического вызова в нейтральных терминах. Например, когда DLR встречает код C#, подобный следующему:
dynamic d = GetSomeData();
d.SuperMethod(12);
то автоматически строит дерево выражения, которое, по сути, гласит: "Вызвать метод по имени SuperMethod на объекте d, передав 12 в качестве аргумента". Эта информация (формально называемая рабочей нагрузкой (payload)) затем передается корректному средству привязки времени выполнения, которое, опять-таки, может быть динамическим средством привязки C#, динамическим средством привязки IronPython или даже унаследованными объектами СОМ.
Отсюда запрос отображается на необходимую структуру вызовов для целевого объекта. Замечательным в деревьях выражений является то (помимо того факта, что вам не нужно создавать их вручную), что они позволяют нам написать фиксированный оператор кода C#, не заботясь о том, что собой представляет его реальная цель (объект СОМ, код IronPython или IronRuby, и т.п.). На рисунке иллюстрируется концепция деревьев выражений на наивысшем уровне:
Пространство имен System.Dynamic
В версии .NET 4.0 к сборке System.Core.dll было добавлено пространство имен System.Dynamic. По правде говоря, шансы, что вам когда-либо придется непосредственно использовать типы из этого пространства имен, весьма невелики. Однако если вы — разработчик языка, который желает обеспечить своему динамическому языку возможность взаимодействия с DLR, пространство имен System.Dynamic пригодится для построения специального средства привязки времени выполнения.
Подробные сведения о типах System.Dynamic можно найти в документации .NET Framework 4.0 SDK. Для практических нужд просто знайте, что это пространство имен предоставляет необходимую инфраструктуру, позволяющую обеспечить динамическим языкам взаимодействие с .NET.
Динамический поиск в деревьях выражений во время выполнения
Как уже объяснялось, среда DLR передает деревья выражений целевому объекту, однако на этот процесс оказывает влияние несколько факторов. Если динамический тип данных указывает в памяти на объект СОМ, то дерево выражения посылается низкоуровневому интерфейсу СОМ по имени IDispatch. Как вам может быть известно, этот интерфейс представляет собой способ, которым СОМ включает собственный набор динамических служб. Объекты СОМ, однако, могут использоваться в приложении .NET без применения DLR или ключевого слова C# dynamic. Однако это ведет к более сложному кодированию C#.
Если динамические данные не указывают на объект СОМ, то дерево выражения может быть передано объекту, реализующему интерфейс IDynamicObject. Этот интерфейс используется "за кулисами", чтобы позволить такому языку, как IronRuby, принять дерево выражения DLR и отобразить его на специфику языка Ruby.
Наконец, если динамические данные указывают на объект, который не является объектом СОМ и не реализует интерфейс IDynamicObject, то это — нормальный, повседневный объект .NET. В этом случае дерево выражения передается на обработку средству привязки исполняющей среды C#. Процесс отображения дерева выражений на специфику .NET включает участие служб рефлексии.
Как только дерево выражения обработано определенным средством привязки, динамические данные размещаются в реальный тип данных в памяти, после чего вызывается корректный метод со всеми необходимыми параметрами.