- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
Делегаты и отражение
Все примеры использования делегатов, показанные до сих пор, требовали, чтобы разработчик заранее знал прототип метода обратного вызова. Так, если fb — переменная, ссылающаяся на делегат Feedback, код для вызова делегата будет примерно такой:
fb(item); // Параметр item определен как Int32.
Как видите, во время кодирования разработчик должен знать, сколько параметров требует метод обратного вызова и тип каждого из них. К счастью, у вас почти всегда есть эта информация, поэтому написать код вроде предыдущего — не проблема.
Но порой у разработчика нет этих сведений на момент компиляции. Достаточно вспомнить пример из главы 10, в котором обсуждался тип EventSet. В этом примере словарь поддерживается набором разных типов делегатов. Чтобы событие сработало во время выполнения, производится поиск и вызов делегата из словаря. При компиляции нельзя точно узнать, какой делегат будет вызван и какие параметры передать его методу обратного вызова.
К счастью, тип System.Delegate предлагает методы, позволяющие создавать и вызывать делегаты, даже если на момент компиляции нет всех сведений о делегате. Вот эти методы:
public abstract class Delegate
{
// Создать делегат «тип», служащий оболочкой заданного статического метода.
public static Delegate CreateDelegate(Type type, Methodlnfo method);
public static Delegate CreateDelegate(
Type type,
Methodlnfo method,
Boolean throwOnBindFailure
);
// Создать делегат «тип», служащий оболочкой заданного экземплярного метода.
public static Delegate CreateDelegate(
Type type, // Эквивалентно this
Object firstArgument,
Methodlnfo method
);
public static Delegate CreateDelegate(
Type type,
Object firstArgument,
Methodlnfo method,
Boolean throwOnBindFailure
);
// Вызываем делегат, передав ему параметры.
public Object DynamicInvoke(params Object[] args);
}
Все версии метода CreateDelegate создают новый объект типа — потомок Delegate, заданного первым параметром type.
Параметр Methodlnfo указывает, что метод должен вызываться по методу обратного вызова; для получения этого значения нужно использовать API отражения (см. главу 22). Если делегат должен быть оболочкой для экземплярного метода, надо передать в CreateDelegate параметр firstArgument, указывающий, что объект нужно передать в экземплярный метод в параметре this (первый аргумент).
Наконец, CreateDelegate генерирует исключение ArgumentException, если делегат не может связаться с методом, указанным в параметре method. Это может произойти, если сигнатура метода method, заданная переменной, не соответствует сигнатуре, требуемой делегатом и заданной в параметре type. Однако если передать в параметре throwOnBindPailure значение false, вместо этого будет возвращено значение null.
Внимание!У класса System.Delegate намного больше перегруженных версий метода CreateDelegate, чем показано здесь. Никогда не следует вызывать ни один из этих других методов. В Microsoft даже жалеют, что вообще определили их. Причина в том, что в остальных методах в процессе привязки вызываемый метод идентифицируется с использованием типа String, а не Metbodlnfo. Это означает, что возможна неоднозначная привязка, приводящая к непрогнозируемому поведению приложения.
Метод Dynamiclnvoke типа SystemDelegate позволяет вызвать метод обратного вызова объекта-делегата, передав набор параметров, определяемых во время выполнения. При вызове Dynamiclnvoke его код проверяет совместимость переданных параметров с параметрами, ожидаемыми методом обратного вызова. Если параметры совместимы, выполняется обратный вызов, в противном случае генерируется исключение ArgumentException.
Dynamiclnvoke возвращает объект, который вернул метод обратного вызова. Следующий код демонстрирует использование методов CreateDelegate и Dynamiclnvoke:
using System;
using System.Reflection;
using System.IO;
// Вот несколько разных определений делегатов,
internal delegate Object TwoInt32s(Int32 n1, Int32 n2);
internal delegate Object OneString(String s1);
public static class Program
{
public static void Main(String[] args)
{
if (args.Length < 2)
{
String fileName =
Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
String usage = @"Usage:" +
"{0} {1} delType methodName [Arg1] [Arg2]" +
"{0} where delType must be TwoInt32s or OneString" +
"{0} if delType is TwoInt32s, methodName must be Add or Subtract" +
"{0} if delType is OneString, methodName must be NumChars or Reverse" +
"{0}" +
"{0} Examples:" +
"{0} {1} TwoInt32s Add 123 321" +
"{0} {1} TwoInt32s Subtract 123 321" +
"{0} {1} OneString NumChars Y'Hello there\"" +
"{0} {1} OneString Reverse Y'Hello there\"";
Console.WriteLine(usage, Environment.NewLine, fileName);
return;
// Преобразовываем параметр delType в тип делегата.
Type delType = Type.GetType(args[0]);
if (delType == null)
{
Console.WriteLine("Invalid delType argument: " + args[0]);
return;
}
Delegate d;
try
{
// Преобразовываем параметр Arg1 в метод.
MethodInfo mi = typeof(Program).GetMethod(args[1], BindingFlags.NonPublic | BindingFlags.Static);
// Создаем объект-делегат, служащий оболочкой статического метода.
d = Delegate.CreateDelegate(delType, mi);
}
catch (ArgumentException)
{
Console.WriteLine("Invalid methodName argument: " + args[1]);
return;
}
// Создаем массив, который содержит только параметры,
// передаваемые методу через объект-делегат.
Object[] callbackArgs = new Object[args.Length - 2];
if (d.GetType() == typeof(TwoInt32s))
{
try
{
// Преобразуем параметры типа String в параметры типа Int32.
for (Int32 a = 2; a < args.Length; a++)
callbackArgs[a - 2] = Int32.Parse(args[a]);
}
catch (FormatException)
{
Console.WriteLine("Parameters must be integers."); return;
}
}
if (d.GetType() == typeof(OneString))
{
// Просто копируем параметр типа String.
Array.Copy(args, 2, callbackArgs, 0, callbackArgs.Length);
}
try
{
// Вызываем делегат и показываем результат.
Object result = d.DynamicInvoke(callbackArgs);
Console.WriteLine("Result = " + result);
}
catch (TargetParameterCountException)
{
Console.WriteLine("Incorrect number of parameters specified.");
}
}
}
// Это метод обратного вызова, принимающий два параметра Int32.
private static Object Add(Int32 n1, Int32 n2)
{
return n1 + n2;
}
// Это метод обратного вызова, принимающий два параметра Int32.
private static Object Subtract(Int32 n1, Int32 n2)
{
return n1 - n2;
}
// Это метод обратного вызова, принимающий один параметр String.
private static Object NumChars(String s1)
{
return s1.Length;
}
// Это метод обратного вызова, принимающий один параметр String.
private static Object Reverse(String s1)
{
Char[] chars = s1.ToCharArray();
Array.Reverse(chars);
return new String(chars);
}
}
Вопрос № 19