- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
Поддержка цепочек делегатов в с#
Компилятор С# облегчает жизнь разработчикам, автоматически предоставляя перегрузку операторов «+=» и «-=» для типов делегатов. Эти операторы вызывают методы Delegate.Combine и Delegate.Remove соответственно. Они упрощают построение цепочек делегатов. В результате компиляции методов ChainDelegateDemo1 и ChainDelegateDemo2 (см. пример в начале главы) получается абсолютно идентичный IL-код. Единственная разница в том, что исходный код ChainDelegateDemo2 проще за счет использования операторов «+=» и «-=» языка С#.
Расширенное управление цепочкой делегатов
Вы уже поняли, как строить цепочки объектов-делегатов и как вызывать все объекты в таком списке. Поскольку метод Invoke типа делегата включает код, итеративно перечисляющий все элементы массива, вызываются все элементы цепочки. Видно, что это очень простой алгоритм. Хотя для большинства сценариев достаточно и такого простого алгоритма, у него много ограничений. Например, отбрасываются все значения, возвращаемые методами обратного вызова, кроме последнего. Остальные значения, возвращаемые методами обратного вызова, невозможно получить при использовании простого алгоритма, но это ограничение — не единственное. А если один из вызванных делегатов генерирует исключение или надолго заблокируется? Поскольку алгоритм последовательно вызывает все делегаты цепочки, «проблема» с одним из делегатов в цепочке остановит вызов остальных. Ясно, что такой алгоритм ненадежен.
Для ситуаций, в которых такого алгоритма недостаточно, класс MulticastDelegate предлагает экземплярный метод GetlnvocationList, позволяющий явно вызвать любой из делегатов цепочки по любому алгоритму, соответствующему вашим потребностям:
public abstract class MulticastDelegate : Delegate
{
// Создает массив делегатов, в котором
// каждый элемент соответствует делегату цепочки.
public sealed override Delegated GetlnvocationList();
}
Метод GetlnvocationList принимает объект, производный от MulticastDelegate, и возвращает массив ссылок на массив ссылок на Delegate, в котором каждая ссылка указывает на один из объектов-делегатов цепочки.
Код GetlnvocationList создает массив и инициализирует его элементами, каждый из которых ссылается на один делегат в цепочке; в конце возвращается ссылка на массив. Если значение поля _invocationList равно null, возвращаемый массив содержит один элемент, который ссылается на единственный делегат цепочки, на экземпляр самого делегата.
Можно без труда написать алгоритм, явно вызывающий каждый объект массива:
using System;
using System.Text;
// Определяем компонент Light.
internal sealed class Light
{
// Этот метод возвращает состояние объекта Light.
public String SwitchPosition()
{
return "The light is off";
}
}
// Определяем компонент Fan.
internal sealed class Fan
{
// Этот метод возвращает состояние объекта Fan.
public String Speed()
{
throw new InvalidOperationException("The fan broke due to overheating");
}
}
// Определяем компонент Speaker.
internal sealed class Speaker
{
// Этот метод возвращает состояние объекта Speaker.
public String Volume()
{
return "The volume is loud";
}
}
public sealed class Program
{
// Определение делегатов, позволяющих запрашивать состояние компонента.
private delegate String GetStatus();
public static void Main()
{
// Объявляем пустую цепочку делегатов.
GetStatus getStatus = null;
// Создаем три компонента и добавляем в цепочку делегатов
// методы для проверки их состояния.
getStatus += new GetStatus(new Light().SwitchPosition);
getStatus += new GetStatus(new Fan().Speed);
getStatus += new GetStatus(new Speaker().Volume);
// Отображаем сводный отчет, отражающий
// состояние трех компонентов.
Console.WriteLine(GetComponentStatusReport(getStatus));
Console.ReadLine();
}
// Метод, запрашивающий несколько компонентов
// и возвращающий отчет об их состоянии.
private static String GetComponentStatusReport(GetStatus status)
{
// Если цепочка пуста, то делать нечего.
if (status == null)
return null;
// Построить отчет о состоянии.
StringBuilder report = new StringBuilder();
// Получаем массив, где каждый элемент - это делегат из цепочки.
Delegate[] arrayOfDelegates = status.GetInvocationList();
// Итеративно обрабатываем все делегаты массива.
foreach (GetStatus getStatus in arrayOfDelegates)
{
try
{
// Получаем строку с состоянием компонента и добавляем в отчет.
report.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);
}
catch (InvalidOperationException e)
{
// Генерируем в отчете запись об ошибке для этого компонента.
Object component = getStatus.Target;
report.AppendFormat(
"Failed to get status from {1}{2}{0}Error: {3}{0}{0}",
Environment.NewLine,
((component == null) ? "" : component.GetType() + "."),
getStatus.Method.Name,
e.Message
);
}
}
// Вернуть сводный отчет вызывающему коду.
return report.ToString();
}
}
Скомпоновав и запустив этот код, мы увидим:
The light is off
Failed to get status from Fan.Speed
Error: The fan broke due to overheating
The volume is loud