
- •1. Понятие модуля. Принципы модульного программирования. Понятие объекта как динамического модуля.
- •2. Понятие класса. Понятие метода. Представление метода в виде обычной процедуры. Понятие конструктора и деструктора.
- •3. Понятие свойства. Методы получения и установки значений свойств. Свойства-массивы (в некоторых языках программирования). Индексаторы (в некоторых языках программирования).
- •Информация о типе времени выполнения программы
- •5. Классы в программных модулях. Атрибуты доступа к элементам объектов. Термин «инкапсуляция».
- •Термин «инкапсуляция»
- •Virtual – в базовом классе
- •7. Понятие ссылки на метод объекта (или делегата – в зависимости от языка программирования). Понятие события. Применение ссылок на методы для расширения объектов.
- •8. Понятие метакласса (в некоторых языках программирования). Методы, применяемые к классам. Виртуальные конструкторы (в некоторых языках).
- •Понятие метакласса (в некоторых языках программирования)
- •Виртуальные конструкторы (в некоторых языках)
- •3) Finally – вызвать free.
- •Если глобально-уникальный идентификатор назначается интерфейсу, то он записывается после ключевого слова interface и заключается в квадратные скобки, например:
- •Microsoft Visual Studio
- •Import Network;
- •Var Stat: SocketStat;
- •Var SocketStatCollection: … ;
- •Конструкторы и деструкторы
- •Стандартные конструкторы
- •Создание объектов по значению (на стеке) и по ссылке (в динамической памяти)
- •Операторы new и delete
- •Размещающий оператор new
- •Порядок конструирования и разрушения объектов
- •Вложенные определения классов
- •«Друзья» класса
- •Статические члены класса
- •19. Перегрузка бинарных операторов. Перегрузка унарных операторов. Перегрузка операторов преобразования типа.
- •Индексаторы
- •Механизм вызова событий
- •Создание пользовательских обобщенных коллекций
- •Создание обобщенных интерфейсов
- •Несколько слов о вложенных делегатах
- •25. Понятие итератора в языке c#. Оператор foreach. Оператор yield.
- •И напоследок... Блок finally
- •26. Понятие атрибутов в языке c#. Создание пользовательских атрибутов. Анализ атрибутов во время выполнения программы. Понятие рефлексии (reflection) в языке c#. Сериализация объектов.
- •Что такое метаданные и зачем они нужны?
- •1. Метаданные в .Net обязательны и универсальны.
- •2. Метаданные в .Net общедоступны.
- •3. Метаданные в .Net исчерпывающи.
- •4. Метаданные в .Net расширяемы.
- •5. Метаданные в .Net конструируемы программно.
- •Получение экземпляра класса Type
- •Динамическая загрузка сборок
- •Динамическая загрузка типов
- •Исследование типа
- •Характеристики типа как целого
- •Члены класса
- •Исследование объекта
- •Динамическое создание объекта и вызов методов
- •Создание объекта по его типу
- •Декларативное программирование
- •Новые механизмы абстракции?
- •Динамическое создание типов
- •Роль графов объектов
- •Formatter сериализации
- •XmlSerializer
- •Интерфейсы iFormatter и iRemotingFormatter
- •Точность типов среди форматеров
- •28*. Ооп в языке программирования Smalltalk. Достоинства и недостатки этого языка в сравнениии с языком программирования c#.
Исследование объекта
Итак, предположим, мы изучили класс досконально. Теперь мы знаем о нём всё. Как же воспользоваться этим знанием, если имеется готовый экземпляр класса? Как прочитать его поля, как получить значения его свойств, как вызывать его методы? Давайте для начала научимся читать поля и свойства объекта.
ПРИМЕЧАНИЕ - Эка невидаль, - скажете вы мне. - Прочитать поля и свойства объекта! Что ж тут такого? - Дело в том, что класс, экземпляр которого мы хотим создать и исследовать, не известен в момент написания программы. Более того, он не только не известен, он даже ещё и не написан! Его напишут после того, как программа будет скомпилирована! |
Предположим, у вас имеется ссылка на объект неизвестного типа. В .Net это означает, что имеется ссылка на объект типа Object. Тип Object – это базовый тип CLR, и к нему можно привести любую ссылку (value-типы перед этим должны быть помещены в GC-хип, т.е. должна быть произведена операция boxing'а). У Object есть только базовый набор методов, через которые нельзя напрямую вызвать методы типа, приведенного к Object. Но с помощью Reflection можно динамически получить описание методов, полей или свойств объекта. А с помощью этого описания можно динамически к ним обращаться. Следующий пример считывает список полей и выводит их имена и значения:
public static void TraceObjectFields(Object obj) { foreach (FieldInfo mi in obj.GetType().GetFields()) Console.WriteLine(mi.FieldType.Name + " " + mi.Name + "= " + mi.GetValue(obj); } |
А этот выводит список свойств объекта:
public static void TraceObjectProperties(Object obj) { foreach (PropertyInfo pi in obj.GetType().GetProperties()) Console.WriteLine(pi.PropertyType.Name + " " + pi.Name + " = " + pi.GetValue(obj, null); } |
Динамическое создание объекта и вызов методов
Итак, мы умеем получать исчерпывающую информацию о типе, который ещё неизвестен в момент компиляции. На основе этой информации, имея экземпляр этого типа, мы умеем получать значения его полей и свойств. Для полного владения ситуацией нам остаётся только научиться создавать экземпляры этих типов, а потом ещё и вызывать их методы.
Создание объекта по его типу
При создании объекта вызывается его конструктор. Если вас устраивает вариант создания объекта с вызовом конструктора без аргументов (конструктора по умолчанию), то задача решается очень просто. Например, вот так:
class Class1 { int n = 5;
static void Main() { string className = "App1.Class1"; Type type = Type.GetType(className); Object data = Activator.CreateInstance(type); Console.WriteLine(Trace1.ObjectFields("data", data)); Console.ReadLine(); } } |
Для подобного рода вещей предназначен специальный класс Activator . У него есть набор статических методов CreateInstance, с помощью которых можно создавать объекты, не только имея объект Type, но также по имени сборки и имени класса, или по файлу сборки и имени класса. Среди методов CreateInstance есть и такие, которые позволяют использовать конструкторы с аргументами и задавать пользовательские атрибуты создаваемого класса.
ПРИМЕЧАНИЕ Наряду с классом Activator способностью создавать объекты по их типу обладают классы Assembly, AppDomain и некоторые другие. У них тоже есть методы CreateInstance, работа с которыми ведётся подобным образом. |
Хочу обратить ваше внимание на то, как определялось, что тип, считанный из сборки, реализует необходимый интерфейс. В данном случае не было экземпляра объекта, к которому применялась бы операция as. Поэтому был использован метод IsAssignableFrom класса Type.
Говоря точнее, в большинстве случаев у нас есть возможность создать экземпляр объекта, а потом применить к нему as, но делать так не совсем рационально. Во-первых, создание объекта может быть недешёвым удовольствием, тем более что неизвестно, будем ли мы его использовать в дальнейшем, или он нам не подойдёт. Во-вторых, возможно, что объект всё равно не удастся создать, потому что тип может быть абстрактным классом или интерфейсом. |
Класс Type имеет ещё один метод со схожей функциональностью – IsInstanceOfType. В отличие от IsAssignableFrom он принимает в качестве аргумента не объект Type, а экземпляр объекта. Метод IsInstanceOfType определяет, является ли тип объекта, переданного в аргументе, наследником типа, для которого этот метод вызван. Иначе можно это сформулировать вот так:
type.IsInstanceOfType(obj) = obj.GetType().IsAssignableFrom(type) |
Если речь зашла о приведениях типов и о выяснении того, кто чей предок, то нельзя не коснуться операций is и as. Честно говоря, я начал немного путаться в этих функциях и операциях, и сделал себе такую табличку. Может, она и вам пригодится?
Возвращаемое значение |
Применяется к: |
Оператор или функция |
Тип аргумента |
Комментарий |
bool |
Object |
is |
тип |
Оператор is позволяет определить, является ли объект (Object) наследником некоторого класса или интерфейса. Оператор также применим к массивам, и позволяет узнать, является ли объект массивом, совместимым с заданным типом. |
Object |
Object |
as |
тип |
Оператор as пытается привести ссылку на объект или интерфейс (Object) к некоторому типу (возможно, интерфейсу). Если это невозможно (в смысле is), возвращается null. |
bool |
Type |
IsInstanceOfType |
Object |
Позволяет определить, является ли некоторый экземпляр объекта (Object) экземпляром указанного типа (Type). |
bool |
Type |
IsSubclassOf |
Type |
Позволяет определить, что тип является наследником типа, переданного в качестве аргумента, и не является абстрактным. Если типы одинаковые, возвращается false. |
bool |
Type |
IsAssignableFrom |
Type |
Позволяет определить, что в переменную данного типа можно установить значение, тип которого указан в качестве параметра метода IsAssignableFrom. Также говорит о возможности приведения типов. |