Главная страница   /   2.1. Необходимость рефлексии (Метапрограммирование в .NET

Метапрограммирование в .NET

Метапрограммирование в .NET

Кевин Хазард

2.1. Необходимость рефлексии

Рефлексия является концепцией, которая существовала долгое время во многих языках программирования, еще до .NET. Рефлексия – это все о предоставлении разработчику возможности читать содержание программы и выполнять ее код. Глубина рефлексии, которую предлагают языки и платформы, варьируется, но в целом любая система, которая позволяет изучать и вызывать код во время выполнения, использует некоторую форму рефлексии.

Давайте рассмотрим два сценария, с которыми может столкнуться .NET разработчик, когда рефлексия действительно может показать свою мощь.

Создание расширяемых приложений

Довольно непросто написать код, который хорошо работает. Хорошие разработчики пересматривают свою работу с членами команды, пишут юнит тесты, используют аналитику и так далее. И определения всех возможностей, которые должно иметь приложение, - это не самая простая деятельность. Пользователи всегда просят новых возможностей, что и понятно. Рынки и бизнес быстро меняются, поэтому они хотят, чтобы их приложения также были гибкими. Если разработчик создает тесно связанные приложения, то добавление новых возможностей с течением времени может быть затруднено. Но с небольшой работой и пониманием ваши приложения будет легче расширять.

Скажем, у вас есть приложение, где нужно отобразить различные отчеты на основе определенного набора данных. Если бы вы написали приложение, которое должно было бы иметь явные знания обо всех докладах, которые ему нужны, чтобы показать отчет для версии 1, добавление новых отчетов могло бы потребовать полного нового развертывания приложения. Без рефлексии ваше приложение является статическим и негибким. Но, допустим, вы решили применить этот подход:

  • Вы создаете интерфейс IReport, который разработчики могут реализовать, чтобы создавать свои собственные отчеты на основе общего интерфейса.
  • Вы добавляете код, который ищет сборки в определенной директории, загружает их в память и ищет все типы, которые реализуют этот интерфейс.
  • Вы создаете экземпляры этих типов и вызываете членов этих типов в качестве ссылки переменной IReport.

Теперь ваше приложение является расширяемым. У вас есть общий путь для других разработчиков, чтобы добавлять или подключать новые отчеты для вашего приложения без перекомпиляции всего приложения. Все, что им нужно сделать, это вставить свои собственные отчеты в сборку в известной директории, и приложение подхватит их автоматически. Все это легко поддерживается Reflection API. Рисунок 2-1 показывает, как работает эта конструкция. Конечно, есть много деталей, которые вам нужно знать, чтобы сделать такую систему устойчивой и надежной, но основная концепция находится в пределах досягаемости при помощи рефлексии.

Рисунок 2-1: Высокоуровневый дизайн расширяемого приложения. Новые сборки копируются в директорию, которую основное приложение мониторит на изменения, чтобы загрузить желаемые дополнения.

Управление членами кода во время выполнения

Если вы разработчик, который привык работать с динамическими языками, такими как Ruby или JavaScript, вы чувствуете себя комфортно, работая в системе, где вы можете буквально определить систему, когда она запущена, добавляя функции к объектам. Для опытных C# или VB разработчиков это не является обычной деятельностью, это может даже показаться небезопасным. Почему вы должны хотеть иметь такие динамические программы, когда компилятор ловит ошибки во время компиляции? На самом деле, только в .NET 4.0 в C# был добавлен тип dynamic для поддержки такой модели программирования.

Так почему же C# или VB разработчики хотят использовать технологии динамических языков? Очень просто: это облегчает создание систем на основе соглашения. Ruby on Rails (или RoR) является общим примером фреймворка, который позволяет легко создавать веб приложения на Ruby (как его позиционируют поклонники динамических языков). Классы в RoR создают методы, которые разработчик ожидает использовать, чтобы находить, редактировать и сохранять объекты, глядя на таблицу в базе данных. Это очень упрощенный взгляд на RoR, но мы попали в точку: вам не нужно писать весь шаблонный постоянный код в RoR. Фреймворк все это вам дает. Хотя вы не можете определять новые члены при помощи рефлексии, вы можете вызывать члены при помощи рефлексии, зная имя члена как строку. По своей сути, это то, что делает для вас dynamic С#. Открытые системы, как эта, предоставляют возможности динамического программирования, которые могут сделать конструкцию системы проще.

Современные .NET фреймворки для динамического программирования

Был создан ряд проектов, которые интенсивно используют динамические технологии программирования. Clay (http://clay.codeplex.com) позволяет динамически создавать структуру объекта во время выполнения. Massive (https://github.com/robconery/massive) – это библиотека, которая сильно упрощает подключение типов к определениям таблицы и выполнение произвольных запросов к базам данных. Вы просто обязаны рассмотреть эти фреймворки, чтобы увидеть их во всей красе.

Теперь, когда у вас есть базовое представление о том, что возможно при помощи рефлексии, давайте посмотрим на Reflection API и узнаем, как с ним взаимодействовать.