- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
Явное управление регистрацией событий
Порой методы add и remove, сгенерированные компилятором, далеки от идеала. Ранее я уже говорил о всех проблемах, связанных с безопасностью потоков, существующих в компиляторе C# компании Microsoft. Вообще-то компиляторC# компании Microsoft никогда не обеспечивает максимальную безопасность, если речь идет о программировании безопасного и надежного кода. Чтобы создавать исключительно надежные компоненты, рекомендую всегда использовать прием, описанный в этом разделе — он позволит решить все проблемы безопасности потоков. Впрочем, его можно использовать и для решения других задач. В частности, очень распространенная причина, побуждающая программистов к самостоятельной реализации методов add и remove, — определение в типе множества событий, когда одновременно требуется эффективнее использовать память. В следующем разделе мы разберем такой сценарий подробнее.
К счастью, компилятор C#, как и многие другие, позволяет разработчикам явно реализовывать методы-аксессоры add и remove. Вот как можно модифицировать объект MailManager для обеспечения безопасной для потоков регистрации и отмены регистрации на уведомление о событии:
internal class MailManager
{
// Создаем закрытое зкземплярное поле
// для блокировки синхронизации потоков.
private readonly Object m_eventLock = new Object();
// Создаем закрытое поле, ссылающееся на заголовок списка делегатов,
private EventHandler<NewMailEventArgs> m_NewMail;
// Создаем в классе член-событие.
public event EventHandler<NewMailEventArgs> NewMail
{
// Явно реализуем метод add.
add
{
// Берем закрытую блокировку и добавляем обработчик
// (передаваемый по значению) в список делегатов,
lock (m_eventLock)
{
m_NewMail += value;
}
}
// Явно реализуем метод remove,
remove
{
// Берем закрытую блокировку и удаляем обработчик
// (передаваемый по значению) из списка делегатов,
lock (m_eventLock)
{
m_NewMail -= value;
}
}
}
// Определяем метод, отвечающий за инициирование события
// и информирование об этом зарегистрированных объектов.
// Если класс изолирован, определяем метод как закрытый и невиртуальный.
protected virtual void OnNewMail(NewMailEventArgs e)
{
// Сохраняем поле делегата во временном поле для обеспечения безопасности потоков.
EventHandler<NewMailEventArgs> temp = m_NewMail;
// Если есть зарегистрировавшиеся объекты,
// уведомляем их.
if (temp != null)
temp(this, е);
}
// Создаем метод, преобразующий входную информацию
// в требуемое событие.
public void SimulateNewMail(String from, String to, String subject)
{
// Создаем объект, хранящий информацию, которую нужно передать
// объектам, получающим уведомление о событии.
NewMailEventArgs е = new NewMailEventArgs(from, to, subject);
// Вызываем виртуальный метод, уведомляющий наш объект о возникновении события.
// Если нет типа, переопределяющего этот метод,
// наш объект уведомит все объекты, подписавшиеся
// на уведомление о событии.
OnNewMail(e);
}
}
В новой версии объекта MailManager закрытое поле m_NewMail, ссылающееся на список делегатов, должно определяться явно. В оригинальном синтаксисе события компилятор C# автоматически определял закрытое поле. В новом синтаксисе, в котором разработчик явно предоставляет реализацию методов-аксессоров add и remove, поля также должны объявляться явно.
Это поле просто представляет собой ссылку на делегат EventHandler<NewMailEventArgs>. Нет ничего, что превращает это поле в событие. В новом расширенном синтаксисе после ключевого слова event следует то, что собственно определяет событие в типе. В блоках add и remove содержится реализация методов-аксессоров. Заметьте: каждый метод принимает скрытый параметр по имени value типа EventHandler<NewMailEventArgs>. Код внутри методов выполняет все операции по добавлению и удаление делегатов из списка. В отличие от свойств, у которых есть оба или хотя бы один метод-аксессор get или set, у событий всегда должны быть оба метода-аксессора add и remove.
Явная реализация методов-аксессоров, показанная в предыдущем примере, работает как методы-аксессоры, сгенерированные компилятором C#, если не считать отсутствия атрибута [MethodImpl(MethodImplOptionsSynchronized)], а вместо этого используется оператор lock языка С# со ссылкой на закрытый определенный объект meventLock типа Object. Именно так я решаю проблему небезопасности потоков, о которой говорил в предыдущем разделе. Поскольку поле m_eventLock объявляется как закрытое, никакой код, за исключением кода класса MailManager, не в состоянии получить доступ к нему; за счет этого повышается надежность класса MailManager.
Событие можно объявлять как статический член, отчего методы-аксессоры также становятся статическими. Естественно, что закрытое поле mJSIewMail также станет статическим. В таком случае для обеспечения безопасности потоков поле m_eventLock также нужно объявить статическим. Это применимо как к ссылочным, так и значимым типам, в которых требуется предоставить статическое событие безопасно для потоков. К сожалению, как говорилось в предыдущем разделе, не существует хорошего способа сделать события экземпляров значимого типа безопасными с точки зрения потоков из-за того, что нет хорошего способа инициализировать экземплярное поле в значимом типе. За объяснением причин отсылаю вас к главе 5.
Код, регистрирующий и отменяющий регистрацию события, не различает методы add и remove, созданные автоматически компилятором или явно реализованные разработчиком. На самом деле это не исключает возможности использования в исходном тексте операторов += и -=, при этом компилятор будет знать, что следует сгенерировать вызовы явно определенных методов.
И последнее замечание относительно метода OnNewMail. Семантически этот метод идентичен предыдущей версии. Единственная разница в том, что имя события (NewMail) заменено на имя поля делегата, m_NewMail.