<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=291406&amp;view=findpost&amp;p=2464754</guid>
        <pubDate>Sun, 03 Jan 2010 14:26:47 +0000</pubDate>
        <title>Асинхронное программирование</title>
        <link>https://forum.sources.ru/index.php?showtopic=291406&amp;view=findpost&amp;p=2464754</link>
        <description><![CDATA[juice: В прошлой статье посвященной асинхронной модели программирования мы рассмотрели шаблон базирующийся на событиях и я пообещал в следующей своей статье рассмотреть альтернативную модель которая использует APM (Asynchronous Programming Model) паттерн. Как было сказано в предисловии к первой статье данный подход нацелен на потребителей которым является библиотечный код. Мы не будем пытаться больше синхронизировать наш код с потоком в котором выполняется GUI приложения, а в замен получим большую гибкость и несколько возможных сценариев получения результатов выполнения кода. Начнем.  Для тестирования нашего кода используем следующую программную модель.<br>
Класс  DirectoryDescriptor<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;public class DirectoryDescriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public string Name { get; set; }</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public string Path { get; set; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
<br>
Класс описывает физический каталог (имя, путь).<br>
Класс DirectoryManager инкапсулирующий логику по работе с директориями. Один из его методов позволяет  получить список каталогов по заданному пути. Ниже приводится тестовая реализация:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;public class DirectoryInfoManager</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IList&#60;DirectoryDescriptor&#62; EnumDirectories(string path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(from d in Directory.GetDirectories(path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select new DirectoryDescriptor {Name = Path.GetFileName(d), Path = d}).ToList();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
Итак мы имеем синхронное API. Наша цель применив APM паттерн добиться того, что бы наш код по получению информации о директориях мог выполняться асинхронно.<br>
Согласно утвердившийся практике, APM API должен предоставить два метода с префиксами Begin и End. Первый позволяет вызывать метод асинхронно, второй позволяет получить результат его выполнения и обработать возможные сообщения об ошибках, читай исключения . Стандартная реализация APM требует обеспечения четырех возможных способов получения результата работы асинхронного кода.<br>
1)	Посредством callback метода передаваемого в метод Begin<br>
2)	Посредством использования WaitHandle для получения уведомления о том, что код выполнен.<br>
3)	Проверкой флага состояния о  выполнении кода<br>
4)	Прямым вызовом метода с префиксом End, в этом случае нам нужно обеспечить внутрению модель ожидания выполнения кода и получения результатов его выполнения.<br>
Прежде, чем двинуться дальше мы могли бы подумать  о том, что бы мы могли написать для предоставления  таких возможностей клиенту.  С callback методом все просто мы могли бы его принять параметром в метод Begin и вызвать когда наш код выполниться, при этом мы могли бы написать некий вспомогательный код, который позволял бы передавать и сам метод для выполнения.   В нашем случае это была бы синхронная реализация.  В конечном итоге это чем то напоминает событийную модель за тем лишь исключением, что результат работы будет получен клиентом не из аргументов события, а внутри callback метода путем вызова метода End. Для того, что бы выполнить пункт 2 нам потребуется вернуть из метода Begin клиенту ссылку на ManualResetEvent, клиент сможет ожидать уведомление об окончании выполнения метода Begin и получив его сможет воспользоваться результатом его работы вызвав соответствующий метод End. Аналогично пункт 3 предпологает возврат флага, проверяя который клиент получит возможность дождаться окончания выполнения Begin метода. Отсюда легко сделать вывод, что нам потребуется некий класс являющий собой агрегат для WaitHandle и управляющего флага. Имея WaitHandle несложно добиться синхронизации работы при прямом вызове метода End. Посредством такого класса было бы удобно и передать результаты работы метода Begin.<br>
Для поддержки всех  четырех возможных сценариев .NET Framework предлагает нам самостоятельно реализовать IAsyncResult интерфейс. С его помощью клиент нашего класса, сможет синхронизировать свой код и получит возможность извлекать результат работы метода BeginXXX.<br>
Давайте взгляним на этот интерфейс:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public interface IAsyncResult</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;// Properties</div><div class="code_line">&nbsp;&nbsp; &nbsp;object AsyncState { get; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;WaitHandle AsyncWaitHandle { get; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;bool CompletedSynchronously { get; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;bool IsCompleted { get; }</div><div class="code_line">}</div></ol></div></div></div></div><br>
<br>
<br>
Что же мы видим? По порядку AsyncState некий объект состояния  по которому клиент сможет отличать один ассинхронный вызов от другого. В большинстве ситуации равен null. <br>
AsyncWaitHandle - обычно экземпляр класса ManualResetEvent, который позволит сообщить о событии завершения кода из одного потока в другой. <br>
CompletedSynchronously – отвечает за уведомление клиента о том, что код выполнится синхронно, в нашем случае это не актуально и мы будем всегда возвращать false.<br>
IsCompleted – булева переменная проверяя которую клиент может узать о том, что пришло время узнать о результатах выполнения ассинхронного кода.<br>
По сути очень похоже на обобщение поведения для всех наших 4-x способов получить результат выполнения.  Реализовав такой интерфейс и вернув экземпляр такого класса из метода Begin, мы сможем обеспечить выполнение пунктов 2, 3, 4 для клиента нашего класса, а добавив callback параметром в метод Begin, мы выполним и пункт под номером 1. Общий вид метода BeginXXX будет следующим:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">IAsyncResult BeginXXX(те же парамметры, что и для синхронного метода, AsyncCallback callback, object state);</div></ol></div></div></div></div>Для метода EndXXX будет <br>
<br>
справедлив следующий шаблон:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">ТипВозвратКакВсинхронойВерсии EndXXX(IAsyncResult result);</div></ol></div></div></div></div><br>
<br>
Применив такие шаблоны к нашему менеджеру мы получим следующий код:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IList&#60;DirectoryDescriptor&#62; EnumDirectories(string path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(from d in Directory.GetDirectories(path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select new DirectoryDescriptor {Name = Path.GetFileName(d), Path = d}).ToList();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IAsyncResult BeginEnumDirectories(string path, AsyncCallback callback, object state)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IList&#60;DirectoryDescriptor&#62; EndEnumDirectories(IAsyncResult asyncResult)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
Что бы наполнить методы реализацией нам потребуется реализовать интерфейс IAsyncResult для этого мы создадим класс DirectoryInfoAsyncResult<br>
Объявим следующие переменные:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private volatile int _isComplited;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private readonly ManualResetEvent _waitHandle;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private readonly AsyncCallback _callback;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private readonly object _state;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private Exception _currentException;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private IList&#60;DirectoryDescriptor&#62; _result;</div></ol></div></div></div></div><br>
<br>
Остановлюсь на некоторых моментах, которые мне кажутся важными. Прежде всего я решил использовать вместо булевой переменной IsCompleted переменную типа int переменная будет изменяться и мониторится из разных потоков, а потому я страхуясь использую ключевое слово volotile. Стоит заметить, что для CLR это не принципиально и можно использовать переменную типа bool, а вот код под Mono потребует этого в обязательном порядке.<br>
Сам интерфейс реализуется тривиальнейшим способом:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public bool IsCompleted { get { return _isComplited == 1; }}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public WaitHandle AsyncWaitHandle { get { return _waitHandle; }}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public object AsyncState { get{ return _state;} }</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public bool CompletedSynchronously { get { return false; } }</div></ol></div></div></div></div><br>
<br>
Все, что нам осталось сделать это добавить парочку вспомогательных методов:<br>
Первый метод будет иметь возможность запускать код асинхронно:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">private void RunAsynchronously(Func&#60;string, IList&#60;DirectoryDescriptor&#62;&#62; func, string path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ThreadPool.QueueUserWorkItem(o =&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _result = func(path);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch (Exception ex)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _currentException = ex;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; finally</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _isComplited = 1;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _waitHandle.Set();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_callback != null)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _callback(this);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div></ol></div></div></div></div>Метод принимает метод синхронного вызова и выполняет его асинхронно, через пул потоков. В результате либо сохраняет результат или же сохраняет возникший Exception в соответствующую переменную. В любом из двух сценариев мы обеспечиваем возможность получения уведомления о завершении метода: устанавливаем флаг, устанавливаем в сигнальное положение handle, вызываем callback метод.<br>
Теперь вспомогательный метод End:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; public IList&#60;DirectoryDescriptor&#62; End()</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(!IsCompleted)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_waitHandle.WaitOne();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_waitHandle.Close();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (_currentException != null)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw _currentException;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return _result;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
Мы им воспользуемся в реализации EndEnumDirectories, суть происходящего сводится к … дождаться выполнения ассинхронной операции если это нужно и вернуть результат выполнения кода если не возникло никаких осложнений.По сути мы выполнили условие пункта 4 при котором клиент не дождавшись выполнения асинхронной операции вызывает метод EndEnumDirectories (мы дождемся за него :))).<br>
Последний штрих конструктор класса:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public DirectoryInfoAsyncResult(Func&#60;string, IList&#60;DirectoryDescriptor&#62;&#62; func, string path, AsyncCallback callback, object state)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_callback = callback;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_state = state;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_waitHandle = new ManualResetEvent(false);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RunAsynchronously(func, path);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
Мы передаем синхронный метод, аргументы для его выполнения, callback метода и state если это необходимо. Метод сразу же выполняем, а callback и state сохраняем в соответствующие переменные.<br>
Воспользовавшись вышеприведеным кодом мы можем полностью реализовать наш DirectoryInfoManager:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;public class DirectoryInfoManager</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IList&#60;DirectoryDescriptor&#62; EnumDirectories(string path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(from d in Directory.GetDirectories(path)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select new DirectoryDescriptor {Name = Path.GetFileName(d), Path = d}).ToList();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IAsyncResult BeginEnumDirectories(string path, AsyncCallback callback, object state)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return new DirectoryInfoAsyncResult(EnumDirectories, path, callback, state);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public IList&#60;DirectoryDescriptor&#62; EndEnumDirectories(IAsyncResult asyncResult)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var result = (DirectoryInfoAsyncResult)asyncResult;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return result.End();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
Осталось продемонстрировать все четыре способа получения результатов работы:<br>
1)<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var manager = new DirectoryInfoManager();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var ar = manager.BeginEnumDirectories(&quot;D:\&quot;, null, null);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// некий полезный код</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IList&#60;DirectoryDescriptor&#62; directories = manager.EndEnumDirectories(ar);</div></ol></div></div></div></div><br>
<br>
2)<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var manager = new DirectoryInfoManager();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var ar = manager.BeginEnumDirectories(&quot;D:\&quot;, null, null);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// некий полезный код</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while (!ar.IsCompleted)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// некий полезный код</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
            IList&lt;DirectoryDescriptor&gt; directories = manager.EndEnumDirectories(ar);<br>
3)<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var manager = new DirectoryInfoManager();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var ar = manager.BeginEnumDirectories(&quot;D:\&quot;, null, null);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// некий полезный код</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(!ar.AsyncWaitHandle.WaitOne(1000, false))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// выводим прогресс работы</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IList&#60;DirectoryDescriptor&#62; directories = manager.EndEnumDirectories(ar);</div></ol></div></div></div></div><br>
<br>
4)            <br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var manager = new DirectoryInfoManager();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;manager.BeginEnumDirectories(&quot;D:\&quot;, result =&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IList&#60;DirectoryDescriptor&#62; directories = manager.EndEnumDirectories(result);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, null);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// некий полезный код</div></ol></div></div></div></div><br>
<br>
В заключение: Реализацию DirectoryInfoAsyncResult, очень легко сделать параметризированной на основе generic. Пусть это будет факультативным заданием для тех кто смог дочитать до этого места :)<br>
<br>
До новых встреч.]]></description>
        <author>juice</author>
        <category>.NET FAQ</category>
      </item>
	
      </channel>
      </rss>
	