- •Введение Обзор .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. Круглая форма
- •Собственные элементы управления
- •Литература
Делегаты
Класс, структура, интерфейс, перечисление, делегат – это всё разнообразные категории классов. Каждая категория имеет свои особенности объявления, своё назначение и строго определённую область применения.
Делегат – это тоже класс.
Объявление класса делегата начинается ключевым словом delegate и выглядит следующим образом:
ОбъявлениеКлассаДелегата ::=
[СпецификаторДоступа]
delegate
СпецификаторВозвращаемогоЗначения
ИмяКлассаДелегата
(СписокПараметров);
При этом
СпецификаторВозвращаемогоЗначения ::= ИмяТипа
ИмяКлассаДелегата ::= Идентификатор
а синтаксис элемента СписокПараметров аналогичен списку параметров функции. Но сначала примеры объявления классов делегатов.
delegate int ClassDelegate(int key);
delegate void XXX(int intKey, float fKey);
Подобие объявления класса делегата и заголовка функции не случайно.
Класс делегат способен порождать объекты. При этом назначение объекта-представителя класса-делегата заключается в представлении методов (функций-членов) РАЗЛИЧНЫХ классов.
Тех классов, которые оказываются видимыми из пространства имён, содержащих объявление данного класса-делегата. Объект этого класса способен представлять ЛЮБЫЕ (статические и нестатические) функции-члены классов, лишь бы спецификация их возвращаемого значения и список параметров соответствовали бы характеристикам данного класса-делегата.
В основе любой класс-делегат является многоадресным (multicast delegate). Это означает, что в ходе выполнения приложения делегат способен запоминать ссылки на произвольное количество функций-членов. Эта многоадресность обеспечивается внутренним списком, в который и заносятся ссылки на разнообразные функции-члены, соответствующие заданной сигнатуре и спецификации возвращаемого значения.
Класс-делегат является производным от System.MulticastDelegate, что и позволяет объектам-представителям этого класса реализовывать достаточно сложные алгоритмы настройки на функции-члены различных классов.
Унаследованные свойства и методы классов-делегатов.
Свойства и методы |
Назначение |
Method |
Свойство. Возвращает имя метода, на который указывает делегат. |
Target |
Свойство. Возвращает имя класса, если делегат указывает на нестатический метод класса. Возвращает значение типа null, если делегат указывает на статический метод. |
Combine(), operator+(), operator+=(), operator-(), operator-=() |
Функция и операторные функции. Обеспечивают реализацию многоадресного делегата. Работа с операторными функциями смотрится как прибавление и вычитание ДЕЛЕГАТОВ. Арифметика делегатов. |
GetInvocationList() |
Основываясь на внутреннем списке ссылок на функции, строится соответствующий массив описателей типов функций. Попытка применения метода к пустому делегату приводит к возникновению исключения. |
object DynamicInvoke (object[] args) |
В соответствии со списком ссылок обеспечивается выполнение функций, на которые был настроен делегат. |
static Remove() |
Статический метод, обеспечивающий удаление элементов внутреннего списка ссылок на функции. |
Пример использования возможностей делегата представлен ниже.
using System;
namespace Delegates_1
{
// Класс делегат. Его объявление соответствует типу функции,
// возвращающей значение int с одним параметром типа int.
delegate int xDelegate(int key);
//===========================================
class ASD
{
// Делегат как член класса.
public xDelegate d;
// А вот свойство, которое возвращает ссылку на делегат.
public xDelegate D
{
get
{
return d;
}
}
}
//========================================================
// Класс, содержащий функцию-член, на которую может
// быть настроен делегат-представитель класса xDelegate.
//========================================================
class Q
{
public int QF(int key)
{
Console.WriteLine(“int QF({0})”, key);
return key;
}
// А вот функция, в которой делегат используется как параметр!
public void QQQ(int key, xDelegate par)
{
Console.WriteLine(“Делегат как параметр!”);
// И этот делегат используется по назначению – обеспечивает вызов
// НЕКОТОРОЙ функции. Какой функции? А неизвестно какой! Той,
// на которую был настроен делегат перед тем, как его ссылка была передана
// в функцию QQQ. Здесь не интересуются тем, что за функция пришла.
// Здесь запускается ЛЮБАЯ функция, на которую настраивался делегат.
par(key);
}
}
//===========================================
// Стартовый класс. Также содержит пару пригодных для настройки
// делегата функций.
class StartClass
{
// Одна статическая...
public static int StartClassF0(int key)
{
Console.WriteLine(“int StartClassF0({0})”, key);
return key;
}
// Вторая нестатическая...
public int StartClassF1(int key)
{
Console.WriteLine(“int StartClassF1({0})”, key);
return key;
}
// Процесс пошёл!
static void Main(string[] args)
{//===============================================================
// Ссылка на делегат.
xDelegate localDelegate;
int i, n;
// Объект – представитель класса StartClass.
StartClass sc = new StartClass();
// Объект – представитель класса Q.
Q q = new Q();
// Объект – представитель класса ASD.
ASD asd = new ASD();
// Статическая функция-член класса - в списке делегата.
// Поскольку делегат настраивается непосредственно в
// класса, которому принадлежит данная статическая функция,
// здесь обходимся без дополнительной спецификации имени
// функции.
asd.d = new xDelegate(StartClassF0);
// Вот показали имя метода, на который настроен делегат.
// Попытались показать имя класса – хозяина метода, на который
// настроили делегат. Ничего не получится, поскольку метод
// статический.
if (asd.d.Target != null) Console.WriteLine(asd.d.Target);
// неСтатическая функция-член класса - в списке делегата.
// добавляется к списку функций делегата посредством
// операторной функции +=.
asd.d += new xDelegate(sc.StartClassF1);
Console.WriteLine(asd.d.Method.ToString());
if (asd.d.Target != null) Console.WriteLine(asd.d.Target);
// Делегат также включил в список функцию-член класса Q.
asd.d += new xDelegate(q.QF);
Console.WriteLine(asd.d.Method.ToString());
if (asd.d.Target != null) Console.WriteLine(asd.d.Target);
// Делегат разряжается последовательностью
// вызовов разнообразных функций.
// Либо так.
asd.d(125);
// Либо так. Параметр
// при этом пришлось упаковать в одномерный массив типа object
// длиной в 1.
asd.d.DynamicInvoke(new object[]{0});
// Также есть возможность удаления функции из списка делегата.
// Для этого воспользуемся локальным делегатом.
localDelegate = new xDelegate(q.QF);
asd.d -= localDelegate;
asd.d(725);
// А теперь опять добавим функцию в список делегата.
asd.d += localDelegate;
asd.d(325);
Console.WriteLine(asd.d.Method.ToString());
// А теперь - деятельность по построению массива описателей типа ссылок.
// Преобразование ОДНОГО объекта, содержащего массив ссылок на функции
// в массив объектов, содержащих по одной ссылке на функцию.
// Таким образом, для каждой ссылки на функцию делегата в рамках массива
// делегатов строится свой собственный делегат.
// Естественно что элемент массива, уже не является Multicast'овым делегатом.
// Поэтому с его помощью можно выполнить ОДНУ функцию Multicast’ового делегата.
Console.WriteLine(“—In array!------------------------- ”);
// Вот ссылка на массив делегетов. Сюда будем сгружать содержимое Multicast’а.
Delegate[] dlgArray;
try
{
dlgArray = asd.d.GetInvocationList();
}
catch (System.NullReferenceException e)
{
Console.WriteLine(e.Message + “:Delegate is empty”);
return;
}
// Прочитали содержимое массива описателей типа ссылок.
for (i = 0, n = dlgArray.Length; i < n; i++)
{
Console.WriteLine(dlgArray[i].Method.ToString());
// А можно и так, без помощи метода ToString()… С тем же результатом.
//Console.WriteLine(dlgArray[i].Method);
}
// Вот как запускается ОДНА функция из списка ссылок на функции!
// Используются разные варианты запуска.
Console.WriteLine(“^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^”);
dlgArray[1].DynamicInvoke(new object[]{75});
((xDelegate)(dlgArray[2]))(123);
Console.WriteLine(“^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^”);
// Используем этот массив для преобразования массива ссылок делегата.
// Выкидываем из массива один элемент.
// Возвращаемое значение (НОВЫЙ делегат с изменённым списком)
// может быть “поймано” и другим делегатом!
asd.d = (xDelegate)xDelegate.Remove(asd.d,dlgArray[1]);
// Таблица ссылок модифицированного делегата сократилась!
Console.WriteLine(“Таблица ссылок сократилась! ”);
asd.d(125);
// Через свойство получили ссылку на делегат.
xDelegate dFROMasd = asd.D;
// Таблица ссылок опустошается!
// Ещё бы! Здесь из списка методов одного делегата
// удаляются ВСЕ делегаты, которые встречаются в списке
// методов второго делегата. Буквально: удали из этого списка
// ВСЕ методы, которые в этом списке встретятся!
// Что-то из жизни того парня, который вытягивал сам себя
// за волосы из болота! И если бы НОВЫЙ делегат не был бы
// перехвачен на другую ссылку – весь исходный список
// методов Multicast'ового делегата asd.d был бы потерян.
dFROMasd = (xDelegate)xDelegate.RemoveAll(asd.d,asd.d);
// В чём и можно убедиться вот таким способом!
try
{
dlgArray = dFROMasd.GetInvocationList();
}
catch (System.NullReferenceException e)
{
Console.WriteLine(e.Message + “:Delegate is empty”);
}
// Но только не исходный делегат!
Console.WriteLine(“Но только не исходный делегат!”);
// В чём и можно убедиться вот таким способом!
try
{
dlgArray = asd.d.GetInvocationList();
}
catch (System.NullReferenceException e)
{
Console.WriteLine(e.Message + “:Delegate is empty”);
}
// Вот! исходный объект класса-делегата не пустой!
asd.d(125);
q.QQQ(75,asd.d);
}//===============================================================
}
}