2009-02-19 66 views
2

最近我一直在阅读很多有关异步编程的内容,因为我需要创建一个多线程应用程序。如何创建一个具有异步功能的类(类似于SqlCommand或WebRequest)?

不幸的是,我似乎无法将我最近获得的知识整合到一个凝聚力和有用的单位!

我希望有人可以给我如何构建以下一些要点:

  • 我有一个类,做了很多不同的(耗时)的任务在指定的序列。

  • 我想在我的Winforms UI线程中实例化这个类。例如:

    TaskRunner tr = new TaskRunner(); 
    
  • 我希望能够调用一个BeginAsync()方法(你可以有很多的.NET内置对象做)。例如:

    tr.BeginAsync(); 
    
  • 我想我的课回调到我的UI线程当某些事件发生(有关记录,竣工等)。

  • 我希望能够取消我班的执行。例如:

    tr.CancelAsync(); 
    

如何去构建一个类的内部?我似乎无法找到任何有关SqlCommand或WebRequest的内部结构如何工作的内容。

回答

1

希望这个例子能帮助你。

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果壳中由Joseph阿尔巴哈利采取,第3版 ; Ben Albahari

+0

谢谢,这有点让我心动,但我会继续研究它。 – James 2009-02-19 19:21:56

+0

@Valentin Vasiliev:不幸的是,这不是他正在寻找的模式。他正在寻找基于事件的异步模式。 – casperOne 2009-02-19 19:23:48

+0

基于事件的异步模式通常比较简单,所以我希望他能处理更简单的问题:-) – Valentin 2009-02-20 05:54:37

0

你也应该考虑到有很多内置该功能BackgroundWorker对象时间紧迫或幕后流程。

This article有一个很好的教程概述了整个过程,包括显示进度条。

相关问题