Читаем Язык программирования С# 2005 и платформа .NET 2.0. полностью

Чтобы создать делегат в C#, вы должны использовать ключевое слово delegate. Имя делегата может быть любым. Однако делегат должен соответствовать методу, на который этот делегат будет указывать. Предположим, например, что нам нужно создать делегат с именем BinaryOp, который сможет указывать на любой метод, возвращающий целое число и имеющий целочисленные входные параметры.

// Этот делегат может указывать на любой метод,

// принимающий два целых значения

// и возвращающий целое значение.

public delegate int BinaryOp(int x, int y);

При обработке типов делегата компилятор C# автоматически генерирует изолированный класс, являющийся производным от System.MulticastDelegate. Этот класс (вместе с базовым классом System.Delegate) обеспечивает делегату необходимую инфраструктуру, позволяющую поддерживать список методов, которые должны быть вызваны позднее. Например, если рассмотреть содержимое делегата BinaryOp с помощью ildasm.exe, вы увидите элементы, показанные на рис. 8.2.

Рис. 8.2. Ключевое слово delegate в C# представляет изолированный тип, производный от System.MulticastDelegate

Как видите, генерируемый здесь класс BinaryOp определяет три открытых метода. Метод Invoke() можно назвать главным, поскольку он используется для синхронного вызова методов, поддерживаемых типом делегата, и синхронность здесь означает то, что вызывающая сторона для продолжения работы должна ожидать завершения вызова. Весьма странным кажется тот факт, что синхронный метод Invoke() в C# нельзя вызвать непосредственно. Чуть позже будет продемонстрировано, как Invoke() вызывается опосредованно с помощью соответствующей синтаксической конструкции.

Методы BeginInvoke() и EndInvoke() обеспечивает возможность асинхронного вызова текущего метода во вторичном потоке выполнения. Если у вас есть опыт работы с многопоточными приложениями, вы должны знать, что одной из главных причин, по которым разработчики создают вторичные потоки, является вызов методов, для выполнения которых требуется много времени. И хотя библиотеки базовых классов .NET предлагают целое пространство имен (System.Threading), специально предназначенное для решения задач многопоточного программирования, с помощью делегатов соответствующие функциональные возможности использовать проще.

Но откуда компилятор "знает", как определять методы Invoke(), BeginInvoke() и EndInvoke()? Чтобы понять суть процесса, рассмотрим пример автоматически генерируемого типа класса BinаrуОр (полужирным шрифтом здесь обозначены элементы, заданные определяемым типом делегата).

sealed class BinaryOp: System.MulticastDelegate {

 public BinaryOp(object target, uint functionAddress);

 public void Invoke(int x, int y);

 public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);

 public int EndInvoke(IAsyncResult result);

}

Во-первых, обратите внимание на то, что параметры и возвращаемое значение определяемого здесь метода Invoke() соответствуют определению делегата BinaryOp. Первые параметры членов BeginInvoke() (в данном случае это два целых числа) тоже соответствуют определению делегата BinaryOp, однако BeginInvoke() всегда имеет еще два параметра (типа AsyncCallback и object), которые используются для асинхронного вызова методов. Наконец, возвращаемое значение метода EndInvoke() тоже соответствует исходной декларации делегата, а единственным параметром метода является объект, реализующий интерфейс IAsyncResult.

Рассмотрим еще один пример. Предположим, что мы определили тип делегата, который позволяет указать на любой метод, возвращающий строку и имеющий три входных параметра System.Boolean.

public delegate string MyDelegate(bool a, bool b, bool c);

На этот раз автоматически генерируемый класс выглядит так.

sealed class MyDelegate : System.MulticastDelegate {

 public MyDelegate(object target, uint functionAddress);

 public string Invoke(bool a, bool b, bool c);

 public IAsyncResult BeginInvoke(bool a, bool b, bool c, AsyncCallback cb, object state);

 public string Endlnvoke(IAsyncResult result);

}

Делегаты могут также "указывать" на методы, содержащие любое число параметров out или ref. В качестве примера рассмотрим следующий тип делегата.

public delegate string MyOtherDelegate(out bool a, ref bool b, int c);

Перейти на страницу:

Похожие книги

97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT