Как создать класс с асинхронными возможностями (аналогично SqlCommand или WebRequest)? - PullRequest
2 голосов
/ 19 февраля 2009

В последнее время я много читал об асинхронном программировании, так как мне нужно создать многопоточное приложение.

К сожалению, я не могу собрать свои вновь приобретенные знания в одну сплоченную и полезную единицу!

Я надеюсь, что кто-то может дать мне несколько советов о том, как построить следующее:

  • У меня есть класс, который выполняет множество различных (и трудоемких) задач в указанной последовательности.

  • Я хотел бы создать экземпляр этого класса в моем потоке пользовательского интерфейса Winforms. например:

    TaskRunner tr = new TaskRunner();
    
  • Я хотел бы иметь возможность вызывать метод BeginAsync () (как вы можете это сделать со множеством встроенных объектов .NET). например:

    tr.BeginAsync();
    
  • Я бы хотел, чтобы мой класс вызывал мой поток пользовательского интерфейса при возникновении определенных событий (для ведения журнала, завершения и т. Д.).

  • Я хотел бы иметь возможность отменить выполнение моего класса. например:

    tr.CancelAsync();
    

Как мне построить внутренности этого класса? Кажется, я не могу найти ничего, что говорило бы о том, как могли бы работать внутренние компоненты SqlCommand или WebRequest.

Ответы [ 3 ]

5 голосов
/ 19 февраля 2009

Для этой операции вы хотите использовать асинхронный шаблон на основе событий (в отличие от шаблона проектирования IAsyncResult). Дополнительные сведения см. В разделе документации MSDN под названием «Обзор асинхронных шаблонов на основе событий», расположенном по адресу:

http://msdn.microsoft.com/en-us/library/wewwczdw.aspx

1 голос
/ 19 февраля 2009

Надеюсь, этот пример вам поможет.

public class MessagingServices
{
  public static IAsyncResult BeginReverseEcho (TcpClient client,
                                               AsyncCallback callback,
                                               object userState)
  {
    var re = new ReverseEcho(  );
    re.Begin (client, callback, userState);
    return re;
  }

  public static byte[] EndReverseEcho (IAsyncResult r)
  {
    return ((ReverseEcho)r).End(  );
  }
}

class ReverseEcho : IAsyncResult
{
  volatile TcpClient     _client;
  volatile NetworkStream _stream;
  volatile object        _userState;
  volatile AsyncCallback _callback;
  ManualResetEvent       _waitHandle = new ManualResetEvent (false);
  volatile int           _bytesRead = 0;
  byte[]                 _data = new byte [5000];
  volatile Exception     _exception;

  internal ReverseEcho(  ) { }

  // IAsyncResult members:

  public object AsyncState           { get { return _userState;  } }
  public WaitHandle AsyncWaitHandle  { get { return _waitHandle; } }
  public bool CompletedSynchronously { get { return false;       } }
  public bool IsCompleted
  {
   get { return _waitHandle.WaitOne (0, false); }
  }

  internal void Begin (TcpClient c, AsyncCallback callback, object state)
  {
    _client = c;
    _callback = callback;
    _userState = state;
    try
    {
      _stream = _client.GetStream(  );
      Read(  );
    }
    catch (Exception ex) { ProcessException (ex); }
  }

  internal byte[] End(  )     // Wait for completion + rethrow any error.
  {
    AsyncWaitHandle.WaitOne(  );
    AsyncWaitHandle.Close(  );
    if (_exception != null) throw _exception;
    return _data;
  }

  void Read(  )   // This is always called from an exception-handled method
  {
    _stream.BeginRead (_data, _bytesRead, _data.Length - _bytesRead,
                       ReadCallback, null);
  }

  void ReadCallback (IAsyncResult r)
  {
    try
    {
      int chunkSize = _stream.EndRead (r);
      _bytesRead += chunkSize;
      if (chunkSize > 0 && _bytesRead < _data.Length)
      {
        Read(  );       // More data to read!
        return;
      }
      Array.Reverse (_data);
      _stream.BeginWrite (_data, 0, _data.Length, WriteCallback, null);
    }
    catch (Exception ex) { ProcessException (ex); }
  }

  void WriteCallback (IAsyncResult r)
  {
    try { _stream.EndWrite (r); }
    catch (Exception ex) { ProcessException (ex); return; }
    Cleanup(  );
  }

  void ProcessException (Exception ex)
  {
    _exception = ex;   // This exception will get rethrown when
    Cleanup();         // the consumer calls the End(  ) method.
  }

  void Cleanup(  )
  {
    try
    {
      if (_stream != null) _stream.Close(  );
    }
    catch (Exception ex)
    {
      if (_exception != null) _exception = ex;
    }
    // Signal that we're done and fire the callback.
    _waitHandle.Set(  );
    if (_callback != null) _callback (this);
  }
}

Пример взят из C # 3.0 в двух словах, 3-е издание Джозеф Албахари; Бен Албахари

0 голосов
/ 19 февраля 2009

Вам также следует рассмотреть объект BackgroundWorker , который имеет множество встроенных функций для выполнения интенсивных или скрытых процессов.

В этой статье есть хороший учебник с описанием всего процесса, включая отображение индикатора выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...