- •Сборки (assembly) в среде .Net. Проблема версионности сборок и ее решение.
- •Номер версии в .Net
- •Сведения о версии
- •Номер версии сборки
- •Информационная версия сборки
- •Общая система типов данных в среде .Net. Размерные и ссылочные типы данных. Типы, переменные и значения
- •Пользовательские типы
- •Система общих типов cts
- •Ссылочные типы
- •Типы литеральных значений
- •Неявные типы, анонимные типы и типы, допускающие значение null
- •Упаковка и распаковка размерных типов данных в среде .Net.
- •Производительность
- •Упаковка–преобразование
- •Распаковка-преобразование
- •Ссылочные типы данных. Объектная модель в среде .Net и языке c#.
- •Модели ручной и автоматической утилизации динамической памяти, их сравнительная характеристика. Модель с ручным освобождением памяти
- •Модель с автоматической «сборкой мусора»
- •Модель автоматической утилизации динамической памяти, основанная на сборке мусора. Проблема недетерминизма.
- •Модель автоматической утилизации динамической памяти, основанная на аппаратной поддержке (тегированной памяти).
- •Сборка мусора в среде .Net. Построение графа достижимых объектов.
- •Сборка мусора в среде .Net. Механизм поколений объектов.
- •Модель детерминированного освобождения ресурсов в среде .Net. Интерфейс iDisposable и его совместное использование с завершителем (методом Finalize).
- •«Мягкие ссылки» и кэширование данных в среде .Net.
- •Краткие и длинные слабые ссылки
- •Краткая ссылка
- •Длинная ссылка
- •Правила использования слабых ссылок
- •Динамические массивы в среде .Net и языке c#.
- •Приведение типов в массивах
- •Все массивы неявно реализуют /Enumerable, /Collection и iList
- •Передача и возврат массивов
- •Создание массивов с ненулевой нижней границей
- •Производительность доступа к массиву
- •Небезопасный доступ к массивам и массивы фиксированного размера
- •Делегаты в среде .Net и механизм их работы. Знакомство с делегатами
- •Использование делегатов для обратного вызова статических методов
- •Использование делегатов для обратного вызова экземплярных методов
- •Правда о делегатах
- •Использование делегатов для обратного вызова множественных методов (цепочки делегатов)
- •Поддержка цепочек делегатов в с#
- •Расширенное управление цепочкой делегатов
- •Упрощение синтаксиса работы с делегатами в с#
- •Упрощенный синтаксис № 1: не нужно создавать объект-делегат
- •Упрощенный синтаксис № 2: не нужно определять метод обратного вызова
- •Упрощенный синтаксис № 3: не нужно определять параметры метода обратного вызова
- •Упрощенный синтаксис № 4: не нужно вручную создавать обертку локальных переменных класса для передачи их в метод обратного вызова
- •Делегаты и отражение
- •События в среде .Net; реализация событий посредством делегатов. События
- •Этап 1: определение типа, который будет хранить всю дополнительную информацию, передаваемую получателям уведомления о событии
- •Этап 2: определение члена-события
- •Этап 3: определение метода, ответственного за уведомление зарегистрированных объектов о событии
- •Этап 4: определение метода, транслирующего входную информацию в желаемое событие
- •Как реализуются события
- •Создание типа, отслеживающего событие
- •События и безопасность потоков
- •Явное управление регистрацией событий
- •Конструирование типа с множеством событий
- •Исключительные ситуации и реакция на них в среде .Net. Достоинства
- •Механика обработки исключений
- •Блок try
- •Блок catch
- •Блок finally
- •Генерация исключений
- •Определение собственных классов исключений
- •Исключения в платформе .Net Framework
- •Исключения и традиционные методы обработки ошибок
- •Управление исключениями средой выполнения
- •Фильтрация исключений среды выполнения
- •21 Средства многопоточного программирования в среде .Net. Автономные потоки. Пул потоков.
- •Создание и использование потоков
- •Запуск и остановка потоков
- •Методы управления потоками
- •Безопасные точки
- •Свойства потока
- •Потоки Windows в clr
- •К вопросу об эффективном использовании потоков
- •Пул потоков в clr
- •Ограничение числа потоков в пуле
- •22. Асинхронные операции в среде .Net. Асинхронный вызов делегатов.
- •23. Синхронизация программных потоков в среде .Net. Блокировки.
- •Двойная блокировка
- •Класс ReaderWriterLock
- •Использование объектов ядра Windows в управляемом коде
- •Вызов метода при освобождении одного объекта ядра
- •24. Синхронизация программных потоков в среде .Net. Атомарные (Interlocked-операции). Семейство lnterlocked-методов
- •25. Прерывание программных потоков в среде .Net. Особенности исключительной ситуации класса ThreadAbortException.
- •26. Мониторы в среде .Net. Ожидание выполнения условий с помощью методов Wait и Pulse. Класс Monitor и блоки синхронизации
- •«Отличная» идея
- •Реализация «отличной» идеи
- •Использование класса Monitor для управления блоком синхронизации
- •Способ синхронизации, предлагаемый Microsoft
- •Упрощение кода c# при помощи оператора lock
- •Способ синхронизации статических членов, предлагаемый Microsoft
- •Почему же «отличная» идея оказалась такой неудачной
- •Целостность памяти, временный доступ к памяти и volatile-поля
- •Временная запись и чтение
- •Поддержка volatile-полей в с#
- •27. Асинхронный вызов делегатов.
- •Общие типы (Generics)
- •Инфраструктура обобщений
- •Открытые и закрытые типы
- •Обобщенные типы и наследование
- •Проблемы с идентификацией и тождеством обобщенных типов
- •«Распухание» кода
- •Обобщенные интерфейсы
- •Обобщенные делегаты
- •Обобщенные методы
- •Логический вывод обобщенных методов и типов
- •Обобщения и другие члены
- •Верификация и ограничения
- •Основные ограничения
- •Дополнительные ограничения
- •Ограничения конструктора
- •Другие вопросы верификации
- •Приведение переменной обобщенного типа
- •Присвоение переменной обобщенного типа значения по умолчанию
- •Сравнение переменной обобщенного типа с null
- •Сравнение двух переменных обобщенного типа
- •Использование переменных обобщенного типа в качестве операндов
- •Преимущества использования общих типов
- •29. Итераторы в среде .Net. Создание и использование итераторов.
- •Общие сведения о итераторах
Использование делегатов для обратного вызова множественных методов (цепочки делегатов)
Цепочка делегатов (chaining) — это набор объектов-делегатов, которой позволяет вызывать все методы, представленные делегатами набора.
Чтобы лучше понять принцип работы цепочки, обратите внимание на метод ChainDelegateDemo1. В нем после оператора ConsoleWriteLine я создаю три объекта-делегата, на которые соответственно ссылаются три переменные fb1,fb2 и fb3 (рис. 15-4).
Рис. 15-4. Начальное состояние объектов-делегатов, на которые ссылаются три переменные fbl,fb2 и fb3.
Переменная-ссылка на объект-делегат Feedback должна ссылаться на цепочку или набор делегатов, служащих оболочками методам обратного вызова. Инициализация fbChain значением null говорит об отсутствии методов обратного вызова. Открытый статический метод Combine класса Delegate используется для добавления делегата в цепочку:
fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
При выполнении этой строчки кода метод Combine «видит» попытку объединить null и fb1. Код метода Combine просто возвращает значение fb1, а в переменной fbChain размещается ссылка на тот же объект-делегат, на который ссылается fb1 (рис. 15-5).
Рис. 15-5- Состояние объектов-делегатов после добавления в цепочку второго делегата
Чтобы добавить в цепочку еще один делегат, снова вызывается метод Combine.
fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
Код метода Combine «видит», что fbChain уже ссылается на объект-делегат, и поэтому создает новый объект-делегат. Новый объект-делегат инициализирует свои закрытые поля _target и _methodPtr.
Поле _invocationList инициализируется ссылкой на массив объектов-делегатов.
Первый элемент массива (с индексом 0) инициализируется ссылкой на делегат, служащий оберткой метода FeedbackToConsole (это делегат, на который сейчас ссылается fbChain). Второй элемент массива (индекс 1) инициализируется ссылкой на делегат, служащий оберткой метода FeedbackToMsgBox (на этот делегат ссылается fb2). Наконец, переменной fbChain присваивается ссылка на вновь созданный объект-делегат (рис. 15-6).
Рис. 15-6. Состояние объектов-делегатов после добавления в цепочку второго делегата
Для создания третьего делегата снова вызывается метод Combine.
fbChain = (Feedback)Delegate.Combine(fbChain, fb3);
Видя, что fbChain уже ссылается на объект-делегат, Combine создает новый объект-делегат (рис. 15-7).
Как и раньше, новый объект-делегат инициализирует свои закрытые поля _target и _methodPtr какими-то значениями, а поле _invocationList инициализируется ссылкой на массив объектов-делегатов.
Первый и второй элементы массива (индексы 0 и 1) инициализируются ссылками на те же делегаты, на которые ссылался предыдущий объект-делегат в массиве. Третий элемент массива (индекс 2) инициализируется ссылкой на делегат, служащий оберткой метода FeedbackToFile (на этот делегат ссылается fb3). Наконец, переменной fbChain присваивается ссылка на вновь созданный объект-делегат.
Заметьте: ранее созданный делегат и массив, на который ссылается его же поле _invocationList, теперь подлежат обработке механизмом сборки мусора.
Рис. 15-7. Окончательное состояние объектов-делегатов в готовой цепочке
После выполнения всего кода создания цепочки, переменная fbChain передается методу Counter.
Counter(1, 2, fbChain);
Внутри Counter содержится код, неявно вызывающий метод Invoke по отношению к объекту-делегату Feedback. Когда Invoke вызывается по отношению к делегату, на который ссылается fbChain, делегат обнаруживает, что поле _invocationList не равно null, и инициируется выполнение цикла, итеративно обрабатывающего все элементы массива, путем вызова метода, оболочкой которого служит указанный делегат.
У нас методы вызываются в следующей последовательности: FeedbackToConsole, FeedbackToMsgBox и FeedbackToFile.
В псевдокоде метод Invoke класса Feedback выглядит примерно так:
public void Invoke(Int32 value)
{
Delegate[] delegateSet = _invocationList as Delegate[];
if (delegateSet != null)
{
// Этот массив делегатов указывает делегаты, которые нужно вызвать.
foreach (Feedback d in delegateSet)
d(value);
// Вызываем каждый делегат.
}
else
{
// Этот делегат определяет один метод,
// который нужно вызвать по механизму обратного вызова.
// Вызвать метод обратного вызова для указанного объекта.
_methodPtr.Invoke(_target, value);
// Предыдущая строка - очень приблизительная копия реального кода.
// Происходящее на самом деле не поддается
// иллюстрации средствами С#.
}
}
Делегаты можно удалять из цепочки, вызывая статический метод Remove объекта Delegate.
В конце кода метода ChainDelegateDemo1 есть пример:
fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
Метод Remove сканирует массив делегатов (с конца и до члена с индексом 0), поддерживаемых объектом-делегатом, на который ссылается первый параметр (в нашем примере fbChain). Remove ищет делегат, поля _target и _methodPtr которого совпадают с соответствующими полями второго параметра (в нашем примере нового делегата Feedback). Если Remove находит совпадение и в массиве остается более одного элемента, создается новый объект-делегат — создается массив _invocationList и инициализируется ссылкой на все элементы исходного массива за исключением удаляемого элемента — и возвращается ссылка на новый объект-делегат. При удалении последнего элемента в цепочке Remove возвращает null.
Заметьте:за раз Remove удаляет из цепочки лишь один делегат, а не все делегаты с заданными значениями в полях _target и _methodPtr.
Пока мы рассматривали тип-делегат Feedback, возвращающий значение void. Однако его можно было определить и так:
internal delegate Int32 Feedback(Int32 value);
В этом случае в псевдокоде метод Invoke выглядел бы примерно так:
public Int32 Invoke(Int32 value)
{
Int32 result;
Delegate[] delegateSet = _invocationList as Delegate[];
if (delegateSet != null)
{
// Этот массив делегатов указывает делегаты, которые нужно вызвать.
foreach (Feedback d in delegateSet)
result = d(value); // Вызываем каждый делегат.
}
else
{
// Этот делегат определяет один метод,
// который нужно вызвать по механизму обратного вызова.
//Вызвать метод обратного вызова для указанного объекта.
result = _methodPtr.Invoke(_target, value);
// Предыдущая строка - очень приблизительная копия реального кода.
// Происходящее на самом деле не поддается
// иллюстрации средствами С#.
}
return result;
}
По мере вызова отдельных делегатов массива возвращаемое значение сохраняется в переменной result. По завершении цикла переменная result содержит результат только последнего вызванного делегата (предыдущие возвращаемые значения отбрасываются); это значение возвращается вызывающему коду, вызвавшему Invoke.