2011-08-19 60 views
0

我試圖使用Richter的AsyncEnumerator類實現APM模式。目標是實現從Socket派生的ExtendedSocket類,並提供Begin/EndReceiveFixedBegin/EndSendFixed方法以異步方式發送或接收固定數量的字節。使用AsyncEnumerator實現APM模式時的異常處理

的代碼看起來像這樣(我省略了發送部分,因爲它基本上是相同接收):

class ExtendedSocket : Socket 
{ 

    public ExtendedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) 
     : base(addressFamily, socketType, protocolType) 
    { 

    } 

    public IAsyncResult BeginReceiveFixed(byte[] buffer, SocketFlags socketFlags, AsyncCallback callback, Object state) 
    { 
     AsyncEnumerator ae = new AsyncEnumerator(); 
     return ae.BeginExecute(DoReceiveFixed(ae, buffer, socketFlags), callback, state); 
    } 

    public void EndReceiveFixed(IAsyncResult asyncResult) 
    { 
     AsyncResult ar = asyncResult as AsyncResult; 
     (ar.InitiatingObject as AsyncEnumerator).EndExecute(ar); 
    } 

    private IEnumerator<Int32> DoReceiveFixed(AsyncEnumerator ae, byte[] buffer, SocketFlags socketFlags) 
    { 
     int totalReceivedBytes = 0; 
     while (totalReceivedBytes < buffer.Length) 
     { 
      BeginReceive(buffer, totalReceivedBytes, buffer.Length - totalReceivedBytes, socketFlags, ae.End(), null); 
      yield return 1; 
      totalReceivedBytes += EndReceive(ae.DequeueAsyncResult()); 
     } 
    } 
} 

這工作在我的應用完全沒有問題,但我不知道該如何處理異常在DoReceiveFixed。我想實現在調用EndReceiveFixed時拋出異常(重新拋出異常)的默認APM行爲。

不幸的是,我無法訪問DoReceiveFixed中的AsyncResult對象,因此我不能撥打SetAsCompleted,但AsyncResult對象除外。

我目前的解決方法是使用AsyncEnumerator<Exception>,而不是AsyncEnumerator這樣的:

class ExtendedSocket : Socket 
{ 

    public ExtendedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) 
     : base(addressFamily, socketType, protocolType) 
    { 

    } 

    public IAsyncResult BeginReceiveFixed(byte[] buffer, SocketFlags socketFlags, AsyncCallback callback, Object state) 
    { 
     AsyncEnumerator<Exception> ae = new AsyncEnumerator<Exception>(); 
     return ae.BeginExecute(DoReceiveFixed(ae, buffer, socketFlags), callback, state); 
    } 

    public void EndReceiveFixed(IAsyncResult asyncResult) 
    { 
     AsyncResult ar = asyncResult as AsyncResult; 
     AsyncEnumerator<Exception> ae = ar.InitiatingObject as AsyncEnumerator<Exception>; 
     ae.EndExecute(ar); 
     if (ae.Result != null) 
     { 
      throw ae.Result; 
     } 
    } 

    private IEnumerator<Int32> DoReceiveFixed(AsyncEnumerator<Exception> ae, byte[] buffer, SocketFlags socketFlags) 
    { 
     int totalReceivedBytes = 0; 
     Exception catchedException = null; 
     while (totalReceivedBytes < buffer.Length) 
     { 
      try 
      { 
       BeginReceive(buffer, totalReceivedBytes, buffer.Length - totalReceivedBytes, socketFlags, ae.End(), null); 
      } 
      catch (Exception ex) 
      { 
       catchedException = ex; 
       break; 
      } 
      yield return 1; 
      try 
      { 
       totalReceivedBytes += EndReceive(ae.DequeueAsyncResult()); 
      } 
      catch (Exception ex) 
      { 
       catchedException = ex; 
       break; 
      } 
     } 
     ae.Result = catchedException; 
    } 
} 

這似乎是工作,但我真的不喜歡這種解決方案。有一個更好的方法嗎?也許有一種方法可以從DoFixedReceive內部訪問AsyncResult對象?

回答

0

隨着傑弗裏裏希特的幫助我解決我的問題(see here):

沒有必要趕在一個迭代的所有異常並手動重新拋出它們。 AsyncEnumerator爲我們做到了這一點。

但是請注意您的調試器設置。我需要在常規調試頁面中取消選中「啓用我的代碼」設置。否則,如果在迭代器內發生異常,調試器會在AsyncEnumerator有機會捕獲異常之前處理未處理的異常消息。