- •Сравнительная характеристика технологий .Net и Java.
- •Промежуточный язык il и байт-код Java. Сравнительная характеристика.
- •Основные принципы построения архитектуры .Net.
- •Сборки (assembly) в среде .Net. Проблема версионности сборок и ее решение.
- •Общая система типов данных в среде .Net. Размерные и ссылочные типы данных.
- •Модель автоматической утилизации динамической памяти, основанная на сборке мусора. Проблема недетерминизма.
- •Модель автоматической утилизации динамической памяти, основанная на аппаратной поддержке (тегированной памяти).
- •Сборка мусора в среде .Net. Построение графа достижимых объектов.
- •Сборка мусора в среде .Net. Механизм поколений объектов.
- •Завершение объектов в среде .Net. Метод Finalize. Список завершаемых объектов (finalization queue) и очередь завершения (freachable queue).
- •Динамические массивы в среде. Net и языке c#.
- •События в среде .Net; реализация событий посредством делегатов.
- •Исключительные ситуации и реакция на них в среде .Net.
- •Средства многопоточного программирования в среде .Net. Автономные потоки. Пул потоков.
- •Асинхронные операции в среде .Net. Асинхронный вызов делегатов.
- •Синхронизация программных потоков в среде .Net. Блокировки.
- •Синхронизация программных потоков в среде .Net. Атомарные (Interlocked-) операции.
- •Мониторы в среде .Net. Ожидание выполнения условий с помощью методов Wait и Pulse.
- •Асинхронный вызов делегатов.
- •Итераторы в среде .Net. Создание и использование итераторов.
- •Атрибуты в среде .Net и языке c#. Создание своих атрибутов.
- •Сервисно-ориентированная архитектура (соа) и ее принципы.
- •Технология wcf. Создание сервиса и клиента.
- •Взаимодействие управляемого и неуправляемого кода в среде .Net на примере вызова функций Windows api.
-
События в среде .Net; реализация событий посредством делегатов.
using System;
// Введем собственный делегат, не принимающий
// никаких значений.
delegate void MyDelegate();
// Это тестовый класс, он представляет собой гипотетический
// компонент кнопки.
class Button
{
// Введем общедоступное событие, к которому
// смогут подключаться все желающие.
public event MyDelegate Click;
// Данная функция необходима для того, чтобы
// симулировать событие нажатия на кнопку.
public void SimulateClick()
{
// Вызываем функции, связанные с событием Click,
// предварительно проверив, зарегистрировался
// ли кто-нибудь в данном событии.
if (Click != null)
Click();
}
};
class App
{
static void Main()
{
// Создаем экземпляр класса/компонента.
Button sc = new Button();
// Добавляем обработчик к его событию.
sc.Click += new MyDelegate(Handler);
// Сами вызовем функцию, которая инициирует
// возникновение события нажатия на кнопку.
sc.SimulateClick();
}
// А это функция-обработчик события нажатия на кнопку.
static void Handler()
{
Console.WriteLine("Hello, World!");
}
};
Рассмотрим, какой код поддержки события был создан компилятором. Для этого изучим IL- код.
Во-первых, компилятор создал поле-делегат, в котором хранятся все зарегистрированные обработчики события..field private class MyDelegate Click
Обратите внимание, что поле является закрытым и может быть использовано только из самого класса, исключая даже его потомков (private). Также компилятор создал одноименное специализированное свойство, в котором указаны методы, реализующие внешнюю работу с данным событием. Причем необходимо отметить, что это свойство по умолчанию является общедоступным..event MyDelegate Click
{
.addon instance void Button::add_Click(class MyDelegate)
.removeon instance void Button::remove_Click(class MyDelegate)
}
События — это члены типа, обеспечивающие такого рода взаимодействие. Тип, в котором определены события, как минимум поддерживает:
■ регистрацию статического метода типа или экземплярного метода объекта, заинтересованных в получении уведомления о событии;
■ отмену регистрации статического метода типа или экземплярного метода объекта, получающих уведомления о событии;
■ уведомление зарегистрированных методов о том, что событие произошло.
Типы могут предоставлять эту функциональность при определении событий, так как они поддерживают список зарегистрированных методов. Когда событие происходит, тип уведомляет об этом все зарегистрированные методы.
-
Исключительные ситуации и реакция на них в среде .Net.
private void SomeMethod() {
try {
// Внутрь блока try помещают код, требующий корректного
// восстановления работоспособности или очистки ресурсов.
}
catch (InvalidOperationException) {
// В такие блоки catch помещают код, который должен восстанавливаться
// после исключений типа InvalidOperationException (или любого исключения,
// производного от него).
}
catch (IOException) {
// В такие блоки catch помещают код, который должен восстанавливаться // после исключений типа IOException (или любого исключения, // производного от него).
catch {
// В такие блоки catch помещают код, который должен
// восстанавливаться после исключений любого типа.
// После перехвата исключений их, как правило,
// генерируют повторно.
throw;
}
finally {
// Внутрь блоков finally помещают код, выполняющий очистку ресурсов после любых действий, начатых в блоке try. Код из этого блока исполняется ВСЕГДА независимо от того, было исключение или нет.
}
// Код после блока finally исполняется, если в блоке try не было исключения или если исключение было перехвачено блоком catch и не было сгенерировано то же самое или другое исключение.)
«Допустим, у меня есть приложение, которое должно считать из файла структуру размером в 20 байт, но файл оказался лишь 10-байтовым. В этом случае я не ожидаю встретить конец файла при чтении, но это неожиданно происходит. Наверное, здесь должно возникнуть исключение, не так ли?» Фактически большинство файлов содержит структурированные данные. Довольно редко бывает так, что приложение читает из файла байт за байтом, тут же обрабатывая прочитанные байты, пока не достигнет конца файла. Поэтому я думаю, логичнее будет, если при попытке чтения за пределами файла метод Read всегда будет генерировать исключение.
При разработке типа вы сначала пытаетесь представить себе разнообразные ситуации, в которых будет применяться тип. Сначала определяется имя типа — обычно существительное, например FileStream (файловый поток) или StringBuilder (построитель строк), затем приступают к определению членов (типов данных свойств, параметров методов, возвращаемых значений и т. п.). Особенности определения этих членов становятся программным интерфейсом типа. Эти члены действия обычно обозначаются глаголами — Read (считать), Write (записать), Flush (очистить), Append (присоединить), Insert (вставить), Remove (удалить) и т. п. Если член, обозначающий действие, не может выполнить свою задачу, он должен сгенерировать исключение.
Есть масса причин, по которым вызванный метод может сгенерировать исключение:
■ если недостаточно памяти в стеке, генерируется исключение Stack-Overflowlixception\
■ если не удается обнаружить сборку, в которой определен тип, генерируется исключение PileNotFoundException-,
■ если IL-код метода не поддается верификации, генерируется исключение VetificationException;
■ если недостаточно памяти для JIT-компиляции IL-кода, генерируется исключение OutOJMemoryException.