- •Введение Обзор .Net. Основные понятия
- •Программа на c#
- •Основы языка Пространство имён
- •Система типов
- •Класс и Структура. Первое приближение
- •Литералы. Представление значений
- •Арифметические литералы
- •Логические литералы
- •Символьные литералы
- •Символьные escape-последовательности
- •Строковые литералы
- •Операции и выражения
- •Приоритет операций
- •Приведение типов
- •Особенности выполнения арифметических операций
- •Особенности арифметики с плавающей точкой
- •Константное выражение
- •Переменные элементарных типов. Объявление и инициализация
- •Константы
- •Перечисления
- •Объявление переменных. Область видимости и время жизни
- •Управляющие операторы
- •Синтаксис объявления метода
- •Вызов метода
- •Перегрузка методов
- •Способы передачи параметров при вызове метода
- •Передача параметров. Ссылка и ссылка на ссылку как параметры
- •Сравнение значений ссылок
- •This в нестатическом методе
- •Свойства
- •Обработка исключений
- •Массив. Объявление
- •Инициализация массивов
- •Примеры инициализации массивов
- •Два типа массивов: Value Type and Reference Type
- •Встроенный сервис по обслуживанию простых массивов
- •Реализация сортировки в массиве стандартными методами
- •Подробнее о массивах массивов (jagged array)
- •Массивы как параметры
- •Спецификатор params
- •Main в классе. Точка входа
- •Создание объекта. Конструктор
- •Операция new
- •В управляемой памяти нет ничего, что бы создавалось без конструктора
- •Кто строит конструктор умолчания
- •This в контексте конструктора
- •Перегрузка операций
- •Синтаксис объявления операторной функции
- •Унарные операции. Пример объявления и вызова
- •Бинарные операции
- •Определение операций конъюнкция и дизъюнкции
- •И вот результат…
- •Пример. Свойства и индексаторы
- •Explicit и implicit. Преобразования явные и неявные
- •Наследование
- •Наследование и проблемы доступа
- •Явное обращение к конструктору базового класса
- •Кто строит базовый элемент
- •Переопределение членов базового класса
- •Наследование и new модификатор
- •Полное квалифицированное имя. Примеры использования
- •Прекращение наследования. Sealed спецификатор
- •Абстрактные функции и абстрактные классы
- •Ссылка на объект базового класса
- •Операции is и as
- •Виртуальные функции. Принцип полиморфизма
- •Интерфейсы
- •Делегаты
- •События
- •События и делегаты. Различия
- •Атрибуты, сборки, рефлексия Рефлексия (отражение) типов
- •Реализация отражения. Type, InvokeMember, BindingFlags
- •Атрибуты
- •Сборка. Класс Assembly
- •Класс сборки в действии
- •Разбор полётов
- •Класс System.Activator
- •Версия сборки
- •Файл конфигурации приложения
- •Общедоступная сборка
- •Игры со сборками из gac
- •Динамические сборки
- •Динамическая сборка: создание, сохранение, загрузка, выполнение
- •Ввод-вывод Базовые операции
- •Потоки: байтовые, символьные, двоичные
- •Предопределённые потоки ввода-вывода
- •Функция ToString()
- •Консольный ввод-вывод. Функции-члены класса Console
- •Консольный вывод. Форматирование
- •Функции вывода. Нестандартное (custom) форматирование значений.
- •Консольный ввод. Преобразование значений
- •Файловый ввод-вывод
- •Потоки Процесс, поток, домен
- •Домен приложения
- •Обзор пространства имён System.Threading
- •Многопоточность
- •Виды многопоточности
- •А кто в домене живёт…
- •Класс Thread. Общая характеристика
- •Именование потока
- •Игры с потоками
- •Характеристики точки входа дополнительного потока
- •Запуск вторичных потоков
- •Приостановка выполнения потока
- •Отстранение потока от выполнения
- •Завершение потоков
- •Метод Join()
- •Состояния потока (перечисление ThreadState)
- •Одновременное пребывание потока в различных состояниях
- •Фоновый поток
- •Приоритет потока
- •Передача данных во вторичный поток
- •Извлечение значений (данных) с помощью Callback методов
- •Организация взаимодействия потоков
- •1. Посредством общедоступных (public) данных
- •2. Посредством общедоступных (public) свойств
- •3. Посредством общедоступных очередей
- •Состязание потоков
- •Блокировки и тупики
- •Очереди. Основа интерфейса взаимодействия
- •Безопасность данных и критические секции кода
- •Пример организации многопоточного приложения
- •Очередь как объект синхронизации
- •Синхронизация работы потоков при работе с общими ресурсами
- •1. Организация критических секций
- •2. Специальные возможности мониторов
- •Рекомендации по недопущению блокировок потоков
- •Форма Класс Form
- •Форма: управление и события жизненного цикла
- •Форма: контейнер как элемент управления
- •Разница между элементами управления и компонентами.
- •Свойства элементов управления. Anchor и Dock
- •Extender providers. Провайдеры дополнительных свойств
- •Validating и Validated элементов управления
- •Управление посредством сообщений
- •Стандартный делегат
- •Делегат EventHandler
- •Класс Application
- •События класса Application
- •Примеры перехвата сообщений
- •Метод WndProc
- •Пример переопределения WndProc
- •Контекст приложения
- •Применение классов GraphicsPath и Region. Круглая форма
- •Собственные элементы управления
- •Литература
Реализация отражения. Type, InvokeMember, BindingFlags
Раннее связывание – деятельность, выполняемая на стадии компиляции, позволяющая:
обнаружить и идентифицировать объявленные в приложении типы,
выявить и идентифицировать члены класса,
подготовить при выполнении приложения вызов методов и свойств, доступ к значениям полей-членов класса.
Позднее, динамическое связывание – деятельность, выполняемая непосредственно при выполнении приложения, позволяющая:
обнаружить и идентифицировать объявленные в приложении типы,
выявить и идентифицировать члены класса,
обеспечить в ходе выполнения приложения вызов методов и свойств, доступ к значениям полей-членов класса.
При этом вызов методов и свойств при выполнении приложения обеспечивается методом InvokeMember. Этот метод выполняет достаточно сложную работу и поэтому нуждается в изощрённой системе управления, для реализации которой применяется перечисление BindingFlags. Перечисление также применяется для управления методом GetMethod.
В рамках этого перечисления определяются значения флажков, которые управляют процессом динамического связывания в ходе реализации отражения.
Список элементов перечисления прилагается.
Имя элемента |
Описание |
CreateInstance
|
Определяет, что отражение должно создавать экземпляр заданного типа. Вызывает конструктор, соответствующий указанным аргументам. Предоставленное имя пользователя не обрабатывается. Если тип поиска не указан, будут использованы флаги (Instance | Public). Инициализатор типа вызвать нельзя. |
DeclaredOnly
|
Определяет, что должны рассматриваться только члены, объявленные на уровне переданной иерархии типов. Наследуемые члены не учитываются. |
Default
|
Определяет отсутствие флагов связывания. |
ExactBinding
|
Определяет, что типы представленных аргументов должно точно соответствовать типам соответствующих формальных параметров. Если вызывающий оператор передает непустой объект Binder, отражение создает исключение, так как при этом вызывающий оператор предоставляет реализации BindToXXX, которые выберут соответствующий метод. Отражение моделирует правила доступа для системы общих типов. Например, если вызывающий оператор находится в той же сборке, ему не нужны специальные разрешения относительно внутренних членов. В противном случае вызывающему оператору потребуется ReflectionPermission. Этот метод применяется при поиске защищенных, закрытых и т. п. членов. Главный принцип заключается в том, что ChangeType должен выполнять только расширяющее преобразование, которое никогда не теряет данных. Примером расширяющего преобразования является преобразование 32-разрядного целого числа со знаком в 64-разрядное целое число со знаком. Этим оно отличается от сужающего преобразования, при котором возможна потеря данных. Примером сужающего преобразования является преобразование 64-разрядного целого числа со знаком в 32-разрядное целое число со знаком. Связыватель по умолчанию не обрабатывает этот флаг, но пользовательские связыватели используют семантику этого флага. |
FlattenHierarchy
|
Определяет, что должны быть возвращены статические члены вверх по иерархии. Статические члены — это поля, методы, события и свойства. Вложенные типы не возвращаются. |
GetField
|
Определяет, что должно возвращаться значение указанного поля. |
GetProperty
|
Определяет, что должно возвращаться значение указанного свойства. |
IgnoreCase
|
Определяет, что при связывании не должен учитываться регистр имени члена. |
IgnoreReturn
|
Используется при COM-взаимодействии для определения того, что возвращаемое значение члена может быть проигнорировано. |
Instance
|
Определяет, что в поиск должны быть включены члены экземпляра. |
InvokeMethod
|
Определяет, что метод должен быть вызван. Метод не может быть ни конструктором, ни инициализатором типа. |
NonPublic
|
Определяет, что в поиск должны быть включены члены экземпляра, не являющиеся открытыми (public). |
OptionalParamBinding
|
Возвращает набор членов, у которых количество параметров соответствует количеству переданных аргументов. Флаг связывания используется для методов с параметрами, у которых есть значения методов, и для функций с переменным количеством аргументов (varargs). Этот флаг должен использоваться только с Type.InvokeMember. Параметры со значениями по умолчанию используются только в тех вызовах, где опущены конечные аргументы. Они должны быть последними аргументами. |
Public
|
Определяет, что открытые (public) члены должны быть включены в поиск. |
PutDispProperty
|
Определяет, что для COM-объекта должен быть вызван член PROPPUT. PROPPUT задает устанавливающую свойство функцию, использующую значение. Следует использовать PutDispProperty, если для свойства заданы и PROPPUT, и PROPPUTREF и нужно различать вызываемые методы. |
PutRefDispProperty
|
Определяет, что для COM-объекта должен быть вызван член PROPPUTREF. PROPPUTREF использует устанавливающую свойство функцию, использующую ссылку, вместо значения. Следует использовать PutRefDispProperty, если для свойства заданы и PROPPUT, и PROPPUTREF и нужно различать вызываемые методы. |
SetField
|
Определяет, что должно устанавливаться значение указанного поля. |
SetProperty
|
Определяет, что должно устанавливаться значение указанного свойства. Для COM-свойств задание этого флага связывания эквивалентно заданию PutDispProperty и PutRefDispProperty. |
Static
|
Определяет, что в поиск должны быть включены статические члены. |
SuppressChangeType
|
Не реализован. |
Далее демонстрируется применение класса Type, в частности, варианты использования метода-члена класса Type InvokeMember, который обеспечивает выполнения методов и свойств класса.
using System;
using System.Reflection;
// В классе объявлены поле myField, конструктор, метод String ToString(), свойство.
class MyType
{
int myField;
public MyType(ref int x)
{
x *= 5;
}
public override String ToString()
{
Console.WriteLine(“This is: public override String ToString() method!”);
return myField.ToString();
}
// Свойство MyProp нашего класса обладает одной замечательной особенностью:
// значение поля myField объекта-представителя класса MyType не может быть
// меньше нуля. Если это ограничение нарушается - возбуждается исключение.
public int MyProp
{
get
{
return myField;
}
set
{
if (value < 1)
throw new ArgumentOutOfRangeException(“value”, value, “value must be > 0”);
myField = value;
}
}
}
class MyApp
{
static void Main()
{
// Создали объект-представитель класса MyType
// на основе объявления класса MyType.
Type t = typeof(MyType);
// А это одномерный массив объектов, содержащий ОДИН элемент.
// В этом массиве будут передаваться параметры конструктору.
Object[] args = new Object[] {8};
Console.WriteLine(“The value of x before the constructor is called is {0}.”, args[0]);
// Вот таким образом в рамках технологии отражения производится
// обращение к конструктору. Наш объект адресуется по ссылке obj.
Object obj = t.InvokeMember(
null,
//____________________________
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.CreateInstance, // Вот распоряжение о создании объекта…
//____________________________
null,
null,
args // А так организуется передача параметров в конструктор.
);
Console.WriteLine(“Type: ” + obj.GetType().ToString());
Console.WriteLine(“The value of x after the constructor returns is {0}.”, args[0]);
// Изменение (запись и чтение) значения поля myField. Только что созданного
// объекта-представителя класса MyType. Как известно, этот объект адресуется по
// ссылке obj. Мы сами его по этой ссылке расположили!
t.InvokeMember(
“myField”, // Будем менять значение поля myField…
//______________________________
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.SetField, // Вот инструкция по изменению значения поля.
//_______________________________
null,
obj, // Вот указание на то, ГДЕ располагается объект…
new Object[] {5} // А вот и само значение. Оно упаковывается в массив объектов.
);
int v = (Int32) t.InvokeMember(
“myField”,
//______________________________
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.GetField, // А сейчас мы извлекаем значение поля myField.
//______________________________
null,
obj, // “Работаем” всё с тем же объектом. Значение поля myField
// присваивается переменной v.
null
);
// Вот распечатали это значение.
Console.WriteLine(“myField: ” + v);
// “От имени” объекта будем вызывать нестатический метод.
String s = (String) t.InvokeMember(
“ToString”, // Имя переопределённого виртуального метода.
//______________________________
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.InvokeMethod, // Сомнений нет! Вызываем метод!
//______________________________
null,
obj, // От имени нашего объекта вызываем метод без параметров.
null
);
// Теперь обращаемся к свойству.
Console.WriteLine(“ToString: “ + s);
// Изменение значения свойства. Пытаемся присвоить недозволенное значение.
// И посмотрим, что будет… В конце-концов, мы предусмотрели перехватчик исключения.
try
{
t.InvokeMember(
“MyProp”, // Работаем со свойством.
//______________________________
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.SetProperty, // Установить значение свойства.
//______________________________
null,
obj,
new Object[] {0} // Вот пробуем через обращение к свойству
// установить недозволенное значение.
);
}
catch (TargetInvocationException e)
{
// Фильтруем исключения... Реагируем только на исключения типа
// ArgumentOutOfRangeException. Все остальные «проваливаем дальше».
if (e.InnerException.GetType() != typeof(ArgumentOutOfRangeException)) throw;
// А вот как реагируем на ArgumentOutOfRangeException.
// Вот так скромненько уведомляем о попытке присвоения запрещённого значения.
Console.WriteLine(“Exception! Catch the property set.”);
}
t.InvokeMember(
“MyProp”,
//______________________________
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.SetProperty, // Установить значение свойства.
//______________________________
null,
obj,
new Object[] {2} // Вновь присваиваемое значение. Теперь ПРАВИЛЬНОЕ.
);
v = (int) t.InvokeMember(
“MyProp”,
BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.GetProperty, // Прочитать значение свойства.
null,
obj,
null
);
Console.WriteLine(“MyProp: “ + v);
}
}
Ну вот. Создавали объект, изменяли значение его поля (данного-члена), вызывали его (нестатический) метод, обращались к свойству (подсовывали ему некорректные значения). И при этом НИ РАЗУ НЕ НАЗЫВАЛИ ВЕЩИ СВОИМИ ИМЕНАМИ! В сущности, ЭТО И ЕСТЬ ОТРАЖЕНИЕ.