Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Декларативное программирование

Создание пользовательских обобщенных коллекций | Создание обобщенных интерфейсов | Установка ограничений на параметры обобщенных классов | Обобщенные делегаты | Несколько слов о вложенных делегатах | И напоследок... блок finally | Создание пользовательских атрибутов | Анализ атрибутов во время выполнения программы | Получение экземпляра класса Type | Характеристики типа как целого |


Читайте также:
  1. B. ПРОГРАММИРОВАНИЕ
  2. II) ЛИНЕЙНОЕ ПРОГРАММИРОВАНИЕ
  3. Web-программирование на стороне клиента.
  4. Архитектура и организация подсистемы DMA (КПДП) в ПК. Управляющая информация и программирование
  5. Визуальное объектно-ориентирование программирование. Инкапсуляция, наследование, полиморфизм. Основные объекты и их свойства, методы и события
  6. Лекция 1: введение в программирование.

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

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

[ AttributeUsage(AttributeTargets.Field) ]public class NotTrace: Attribute{}

Чтобы упростить использование этого атрибута, напишем простую вспомогательную функцию:

static bool NeedTrace(FieldInfo fi){ return! Attribute.IsDefined(fi, typeof(NotTrace));}

Теперь можно модифицировать функцию протоколирования, чтобы она выводила только те поля, у которых не задан атрибут NotTrace:

foreach (FieldInfo fi in type.GetFields(...)){ if (! NeedTrace(fi)) continue;... }

Заметьте, что теперь управление выводом полей производится не изменением кода функции протоколирования, а изменением описаний полей – заданием их атрибутов. Другими словами, судьба объекта задаётся при его декларации. Отсюда название данного метода программирования – декларативное программирование.

Код, исполняющийся в design-time

На примере атрибутов мы впервые (я, по крайней мере, впервые) столкнулись с тем, что часть кода, который пишет программист, выполняется в runtime (это как обычно), а часть кода выполняется в момент разработки (design time)! Не просто используются описания типов (декларации), а именно код! Ведь чтобы получить информацию об атрибутах, надо создать экземпляры объектов-атрибутов, а значит, в этот момент отрабатывают конструкторы атрибутов.

Вот как пишет об использовании атрибутов компилятором Э. Гуннерсон [2]:

Когда компилятор находит атрибут X, установленный для класса, он сначала ищет класс, производный от Attribute, с именем X. Не обнаружив такого класса, он начинает искать класс XAttribute. На этот раз поиск заканчивается успешно. После этого компилятор проверяет, можно ли использовать данный атрибут для классов (AttrubuteUsage). Затем начинается поиск конструктора, который бы соответствовал параметрам, указанным при установке атрибута, если такой конструктор найден, компилятор создаёт экземпляр объекта вызовом конструктора с заданными параметрами. При передаче именованных параметров компилятор сопоставляет имя параметра с именем переменной класса или свойства, после чего присваивает переменной или свойству указанное значение. Во всяком случае, так должно происходить на логическом уровне. <...> Существует несколько причин, по которым схема сохранения атрибутов работает не так, как было описано выше. В первую очередь это связано с быстродействием. Чтобы компилятор мог реально создавать объект атрибута, в это время должна работать среда.Net, поэтому компилятор должен был бы работать как управляемый исполняемый файл. Впрочем, создавать объект в действительности и не требуется, поскольку мы всё равно ограничимся сохранением информации. Поэтому компилятор только убеждается в том, что он может создать объект, вызвать конструктор и присвоить значения всех именованных параметров. Параметры атрибута заносятся в небольшой блок двоичных данных, который сохраняется вместе с метаданными объекта.

От себя же добавлю, что такая схема работы компилятора принципиально ничего не меняет. Дело в том, что другие программные инструменты могут создавать объекты атрибутов "на самом деле", да и сам компилятор в следующих версиях.Net Framework вполне может начать работать по алгоритму, близкому к тому, по которому он работает на логическом уровне. Потому нам следует думать об атрибутах как об объектах, которые могут работать в design time.

Новые механизмы абстракции?

Теперь, когда мы завершили краткое рассмотрение методов исследования типов (методов рефлексии), у нас есть повод задуматься над вопросом: "Какое новое качество могут принести методы рефлексии в наши программы. Дают ли они в наши руки принципиально новые возможности? Думаю этот вопрос имеет положительный ответ.

Напомню, что в С++ (а может и во всей идеологии ООП) существуют два принципиально разных подхода к разработке абстрактных алгоритмов и абстрактных структур данных. Первый подход основан на наследовании и виртуальных методах, в основе второго лежат шаблоны.

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

Формулируя алгоритм с помощью абстрактных (виртуальных) методов класса, вы откладываете окончательную реализацию алгоритма на время исполнения программы. Именно тогда, во время исполнения, решается то, какие реальные методы будут участвовать в работе алгоритма. Это зависит от того с какими конкретными объектами придётся работать алгоритму. Можно сказать, что виртуальные методы конкретизируются в runtime. («конкретизация времени исполнения»).

Но заметьте, виртуальными (абстрактными) до сих пор могли быть только методы. А если вам нужно применить тот же самый механизм конкретизации времени исполнения, но по отношению к полям объекта? А если вам необходимы абстрактные структуры данных, конкретизируемые не при компиляции, а во время исполнения? Всё это позволяет сделать reflection. Короче, reflection – это виртуализация всех элементов программы.

Теперь нам позволительно формулировать алгоритмы подобные таким:

«Найди в этой структуре поле обозначающее цену товара и верни её». Перебираем все поля класса, в поисках поля типа Currency. Заметьте вам не надо знать имя поля. Если вы знаете что поле такого типа есть и оно одно – этого достаточно!

«Свяжи поля этой структуры с аргументами той хранимой процедуры на основе типов и имён полей и параметров». В последнем номере русского MSDN отличная статья про подобного рода методы.

«Выведи на консоль поля c атрибутом «видимый» (этим мы только что занимались).

«Предложи пользователю выбрать класс, заполнить параметры его конструктора класса и создай экземпляр этого класса». Эту задачу и многие подобные ей решает программа.Net Explorer описанная в статье этом номере нашего журнала.

У меня складывается впечатление, что наконец то мы с вами стали настоящими хозяевами своих программ! Наконец то нам стало доступно то, что раньше мог делать только «его величество компилятор». Уверен, что эти новые возможности породят совершенно новые классы алгоритмов, новые подходы к программированию, что в свою очередь принесёт новое качество в наши программы. Поживём – увидим.

А пока рассмотрим ещё один приём программирования в среде.Net, тесно связанный с метаданными, и сулящий не менее революционные изменения в методах программирования.


Дата добавления: 2015-11-16; просмотров: 49 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Создание объекта по его типу| Сериализация объектов

mybiblioteka.su - 2015-2024 год. (0.007 сек.)