- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
Этап 4: определение метода, транслирующего входную информацию в желаемое событие
У класса должен быть метод, принимающий некоторую входную информацию и преобразующий его в генерацию события. В примере MailManager метод SimulateNewMail вызывается для оповещения о прибытии нового сообщения в MailManager.
internal class MailManager
{
// Этап 4: определение метода, транслирующего входную
// информацию в желаемое событие.
public void SimulateNewMail(String from, String to, String subject)
{
// Создать объект для хранения информации, которую
// нужно передать получателям уведомления.
NewMailEventArgs е = new NewMailEventArgs(from, to, subject);
// Вызвать виртуальный метод, уведомляющий объект о событии.
// Если ни один из производных типов не переопределяет этот метод,
// объект уведомит всех зарегистрированных получателей уведомления.
OnNewMail(e);
}
}
Метод SimulateNewMail принимает информацию о сообщении и создает новый объект NewMailEventArgs, передавая его конструктору данные сообщения. Затем вызывается OnNewMail, собственный виртуальный метод объекта MailManager, чтобы формально уведомить объект MailManager о новом почтовом сообщении. Обычно это вызывает генерацию события, в результате уведомляются все зарегистрированные объекты. (Как сказано выше, тип, производный от MailManager, может переопределять это действие.)
Как реализуются события
Научившись определять класс с членом-событием, пора поближе познакомиться с самим событием и узнать, как оно работает. В классе MailManager есть строчка кода, определяющая сам член-событие:
public event EventHandler<NewMailEventArgs> NewMail;
При компиляции этой строчки компилятор превращает ее в следующие три конструкции:
// 1. ЗАКРЫТОЕ поле делегата, инициализированное null.
private EventHandler<NewMailEventArgs> NewMail = null;
// 2. ОТКРЫТЫЙ метод add_Xxx (где Xxx - это имя события).
// Позволяет объектам регистрироваться для получения уведомлений о событии.
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_NewMail(EventHandler<NewMailEventArgs> value)
{
NewMail = (EventHandler<NewMailEventArgs>)Delegate.Combine(NewMail, value);
}
// 3. ОТКРЫТЫЙ метод remove_Xxx (где Ххх - это имя события).
// Позволяет объектам отменять регистрацию для получения уведомлений о событии
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_NewMail(EventHandler<NewMailEventArgs> value)
{
NewMail = (EventHandler<NewMailEventArgs>)Delegate.Remove(NewMail, value);
}
Первая конструкция — просто поле соответствующего типа делегата. Оно содержит ссылку на заголовок списка делегатов, которые будут уведомляться при возникновении события. Поле инициализируется значением null, что означает, что нет получателей, ожидающих уведомления о событии. Когда метод регистрирует получателя уведомления, это поле ссылается на экземпляр делегата EventHandler<NewMailEventArgs>, который может в свою очередь ссылаться на дополнительные делегаты EventHandler<NewMailEventArgs>. Когда получатель регистрируется для получения уведомления о событии, он просто добавляет в список экземпляр типа делегата. Ясно, что отказ от регистрации означает удаление соответствующего делегата.
Обратите внимание: в примере поле делегата, NewMail, всегда закрытое, несмотря на то, что исходная строка кода определяет событие как открытое. Причина в предотвращении доступа из кода, не относящегося к определяющему классу. Если бы поле было открытым, любой код мог бы изменить значение поля, в том числе удалить все делегаты, подписавшиеся на событие.
Вторая создаваемая компилятором C# конструкция — метод, позволяющий другим объектам регистрироваться на получение уведомления о событии. КомпиляторC# автоматически присваивает этой функции имя, добавляя приставку add_ к имени события (NewMail). КомпиляторC# также автоматически генерирует код метода, который всегда вызывает статический метод Combine типа System.Delegate. Метод Combine добавляет в список делегатов новый экземпляр и возвращает новый заголовок списка, который снова сохраняется в поле.
Третья и последняя создаваемая компилятором C# конструкция представляет собой метод, позволяющий объекту отказаться от подписки на событие. И этой функции компилятор С# присваивает имя автоматически, добавляя приставку remove_ к имени события (NewMail). Код метода всегда вызывает метод Remove типа System.Delegate. Последний метод удаляет делегат из списка и возвращает новый заголовок списка, который сохраняется в поле.
Заметим также, что оба метода — add и remove — помечены атрибутом MethodImplAttribute (определенным в пространстве имен SystemRuntime.CompilerServices).
Точнее, эти методы помечены как синхронизированные, поэтому они не нарушают безопасность потоков: множество объектов, следящих за событием, может регистрироваться или отменять свою регистрацию одновременно, не нарушая целостность связного списка.
В этом примере методы add и remove являются открытыми, поскольку в соответствующей строке исходного кода событие изначально объявлено как открытое. Если бы оно было объявлено как закрытое, то add и remove, сгенерированные компилятором, тоже были бы объявлены как закрытые. Так что, когда в типе определяется событие, модификатор доступа события определяет, какой код способен регистрироваться и отменять регистрацию для уведомления о событии, но прямым доступом к полю делегата обладает только сам тип. Члены-события также могут объявляться статическими и виртуальными; в этом случае сгенерированные компилятором методы add и remove также будут статическими или виртуальными соответственно.
Помимо генерации этих трех конструкций, компиляторы также генерируют запись с определением события и помещают ее в метаданные управляемого модуля. Эта запись содержит ряд флагов и базовый тип-делегат, а также ссылки на методы-аксессоры add и remove. Эта информация нужна просто для того, чтобы очертить связь между абстрактным понятием «событие» и его методами-аксессорами. Эти метаданные могут использовать компиляторы и другие инструменты, и, конечно же, эти сведения можно получить при помощи класса SystemReflec-tionEventlnfo. Однако сама CLR не использует эти метаданные и во время выполнения требует лишь методы-аксессоры.