Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Троелсен Э. Язык программирования С# 2010 и п...docx
Скачиваний:
108
Добавлен:
21.09.2019
Размер:
6.92 Mб
Скачать

Асинхронная природа делегатов

Если для вас тема многопоточных приложений является новой, вы можете спросить, чем же на самом деле является асинхронный вызов метода. Вы, без сомнения, знаете о том, что для выполнения некоторых программных операций требуется время. Предыдущий метод Add() был исключительно иллюстративным, но представьте себе, что вы построили однопоточное приложение, в котором вызывается метод удаленного объекта, выполняющий сложный запрос к большой базе данных или запись 500 строк текста во внешний файл. Пока не закончится выполнение этих операций, приложение будет казаться зависшим достаточно долгое время. Пока соответствующая задача не будет обработана, все другие возможности программы (такие как, например, активизация меню, выбор элементов в панели инструментов или вывод на консоль) будут недоступны для пользователя.

Но как дать указание делегату вызвать метод в отдельном потоке выполнения, чтобы имитировать одновременное выполнение множества задач? К счастью, нужной для этого способностью автоматически наделяется каждый тип делегата .NET. И более того, для такого вызова вам не требуется углубляться в детали пространства имен System.Threading (хотя, естественно, одно другому не мешает).

Методы BeginInvoke() и EndInvoke()

Когда компилятор C# обрабатывает ключевое слово delegate, динамически генерируемый класс определяет два метода с именами BeginInvoke() и EndInvoke(). Для нашего определения делегата BinaryOp эти методы оказываются следующими.

sealed class BinaryOp : System.MulticastDelegate {

 …

 // Используется для асинхронного вызова метода.

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

 // Используется для извлечения возвращаемого значения

 // вызванного метода.

 public int EndInvoke(IAsyncResult result);

}

Первый набор параметров, передаваемых в BeginInvoke(), формируется на основе формата делегата C# (в случае BinaryOp это два целочисленных значения). Последними двумя аргументами всегда являются System.AsyncCallback и System.Object. Мы рассмотрим роль этих параметров чуть позже, а пока что для каждого из них мы будем использовать null.

Интерфейс System.IAsyncResult

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

public interface IAsyncResult {

 object AsyncState { get; }

 WaitHandle AsyncWaitHandle { get; }

 bool CompletedSynchronously { get; }

 bool IsCompleted { get; }

}

В самом простом случае можно избежать непосредственного вызова этих членов. Требуется только сохранить совместимый с IAsyncResult объект, возвращенный BeginInvoke(), и передать его методу EndInvoke(), когда вы будете готовы получить результат вызова метода. Позже вы увидите, что у вас есть возможность вызывать члены совместимого с IAsyncResult объекта, если вы хотите "участвовать" в процессе извлечения возвращаемого значений метода.

Замечание. Если асинхронно вызывается метод, который не предлагает возвращаемых значений, можно его вызвать и престо "забыть" о нем. В таких случаях нет необходимости сохранять совместимый с IAsyncResult объект и вызывать EndInvoke() (так как нет возвращаемого значения, которое требуется извлечь).