- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
Определение собственных классов исключений
Допустим, вы определяете метод, которому передается ссылка на объект, в типе которого должны быть реализованы интерфейсы IFormattable и IComparable, например так:
internal sealed class SomeType
{
public void SomeMethod(Object o)
{
if (!((o is IFormattable) && (o is IComparable)))
{
throw new MissingInterfaceException(...);
}
// Здесь находится код, обрабатывающий о.
}
}
Поскольку в FCLнет подходящего типа исключения, придется определить типMissinglnterfaceException самостоятельно. Сначала надо выбрать для него базовый тип. Но какой: Exception, ArgumentException или совсем другой?
Если породить MissinglnterfaceException от ArgumentException, то любой существующий код, который перехватывает ArgumentException, будет перехватывать и это новое исключение. С одной стороны, это полезная возможность, с другой — ошибка. Это полезно, потому что любой код, перехватывающий все типы исключений, связанные с аргументами (посредством перехвата ArgumentException), автоматически будет перехватывать новый вид исключений, связанных с аргументами (MissinglnterfaceException). Ошибка — поскольку исключение MissinglnterfaceException идентифицирует новое событие, не предусмотренное кодом, перехватывающим ArgumentException. Определяя тип MissinglnterfaceException, можно подумать, что он так похож на ArgumentException, что должен обрабатываться так же. Однако непредвиденные связи подобного рода могут привести к непредсказуемой работе программы.
Если же породить MissinglnterfaceException прямо от Exception, код станет генерировать новый тип исключений, о котором приложение ничего не знает. Скорее всего при этом возникнет необработанное исключение, которое прервет исполнение приложения. Легко считать такую реакцию программы желательной, так как метод не в состоянии выполнить свою задачу и у приложения нет средств для восстановления. Если приложение перехватит новое исключение, «проглотит» его и продолжит работу, результаты могут быть непредсказуемы и слишком высок риск нарушения безопасности.
Определяя новый тип исключений, продумайте, как будут перехватываться исключения этого типа (не забудьте и о перехвате базового типа этого исключения), затем выберите базовый тип, оказывающий минимальное негативное влияние на вызывающий код.
Определяя собственные типы исключений, вы вольны создавать вложенные иерархии, если это диктуется поставленной задачей. Можно выводить эти иерархии прямо из Exception или другого базового типа. Здесь тоже нужно следить, чтобы создаваемая иерархия имела смысл для тех, кто будет вызывать ваш код. Если определяемый тип не будет базовым для других типов исключений, можно пометить его как sealed.
Базовый тип Exception определяет четыре стандартных конструктора:
Открытый конструктор без параметров (конструктор по умолчанию), создающий экземпляр типа и устанавливающий для всех его полей и свойств значения по умолчанию;
открытый конструктор, принимающий параметр String и создающий экземпляр типа с заданным текстом сообщения;
конструктор, принимающий в качестве параметров строку (String) и экземпляр типа, производного от Exception, и создающий экземпляр с заданными текстом сообщения и внутренним исключением;
закрытый конструктор, принимающий объекты Serializationlnfo и Streaming-Context, которые десериализуют экземпляры объекта, производного от Exception. Заметьте: этот метод должен быть закрытым, если производный от Exception тип является изолированным; также надо позаботиться, чтобы конструктор вызывал такой же конструктор базового класса, чтобы обеспечить корректную десериализацию полей базового класса.
Определяя собственный тип исключений, следует реализовать в нем эти четыре конструктора и вызывать соответствующий конструктор из базового типа. Конечно, ваш тип исключения унаследует все поля и свойства, определенные в Exception. Кроме того, к нему можно добавить собственные поля и аргументы. Скажем, в исключение SystemArgumentException добавлено свойство типа String — ParamName (помимо всего, что наследуется от типа Exception). Тип ArgumentException также определяет новый конструктор (помимо четырех стандартных конструкторов) с дополнительным параметром типа String, инициализирующим свойство ParamName, которое идентифицирует имя параметра, нарушившего допущения метода.
При перехвате ArgumentException можно прочитать свойство ParamName, чтобы точно определить имя параметра, вызвавшего сбой. Стоит ли говорить, что это невероятно удобно при отладке приложения! Если вы на самом деле добавляете поля к собственному типу исключения, проследите, чтобы были определены конструкторы, обеспечивающие их инициализацию. Также не забудьте определить свойства и остальные члены, что возвращают значения полей в код приложения, который перехватывает исключения вашего типа.
Все типы исключений нужно делать сериализуемыми, чтобы обеспечить маршалинг их объектов через границы домена приложения или за пределы машины. Если сделать тип исключения сериализуемым, его можно будет записывать в журнал или базу данных. Чтобы сделать собственный тип исключения сериализуемым, пометьте его атрибутом [Serializable] и реализуйте интерфейс ISerializable с методом GetObjectData (с атрибутом SecurityPermissiori) и специальным конструктором, оба должны принимать параметры Serializationlnfo и StreamingContext. Заметьте: если класс изолированный, конструктор должен быть закрытым, в противном случае конструктор является защищенным. Вот как определять собственный тип исключения:
using System;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
// Разрешаем сериализацию экземпляров DiskFullException. [Serializable]
public sealed class DiskFullException : Exception, ISerializable { // Создаем закрытое поле, private String m_diskpath;
// Определяем неизменяемое свойство, возвращающее это поле, public String DiskPath { get { return m_diskpath; > >
// Переопределяем открытое свойство Message, // чтобы включить в сообщение содержимое поля (если оно задано), public override String Message { get {
if (m_diskpath == null) return base.Message; StringBuilder msg = new StringBuilder(base.Message); msg.AppendFormat(
" (DiskPath={0>){1>",
m_diskpath, Environment.NewLine); return msg.ToStringO;
}
}
// Три открытых конструктора, public DiskFullException() : base() { } public DiskFullException(String message) : base(message) { } public DiskFullException(String message, Exception innerException) : base(message, innerException) { }
// Определяем дополнительные конструкторы, // задающие значение поля.
public DiskFullException(String message, String diskpath) : this(message) { m_diskpath = diskpath; }
public DiskFullException(String message, String diskpath, Exception innerException) : this(message, innerException) { m_diskpath = diskpath; }
// Один конструктор для десериализации.
// Так как это изолированный класс, конструктор должен быть закрытым.
// В противном случае этот конструктор должен быть защищенным.
private DiskFullException(SerializationInfo info, StreamingContext context)
: base(info, context) {
// Десериализация каждого поля.
m_diskpath = info.GetString("DiskPath");
}
// Метод для сериализации; SecurityPermission гарантирует, // что вызывающий код получит информацию о внутреннем состоянии этого объекта. [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] public override void GetObjectData(
Serializationlnfo info, StreamingContext context) {
// Заставляем базовый тип сериализовать свои поля.
base.GetObjectData(info, context);
// Сериализуем поля этого типа.
info.AddValue("DiskPath", m_diskpath);
>
}
Исключения являются стандартным механизмом сообщения об ошибках. Приложения и библиотеки не должны использовать коды возврата для сообщения об ошибках. Использование исключений способствует единообразию при разработке платформы и позволяют сообщать об ошибках таким членам, как конструкторы, которые не могут получить возвращаемый тип. Исключения также позволяют программам обрабатывать ошибки или завершать работу должным образом. Если приложение не обрабатывает созданное исключение, то поведением по умолчанию является завершение его работы.
Приложения должны одинаково обрабатывать ошибки, возникающие при исполнении. Среда CLR предоставляет модель для единообразного уведомления приложений об ошибках. Все операции среды .NET Framework информируют о сбое посредством порождения исключений.