C# 使用AsyncEnumerator实现APM模式时的异常处理

C# 使用AsyncEnumerator实现APM模式时的异常处理,c#,asynchronous,C#,Asynchronous,我试图使用Richter的AsyncEnumerator类实现APM模式。目标是实现一个ExtendedSocket类,该类派生自Socket,并提供Begin/EndReceiveFixed和Begin/EndSendFixed方法来异步发送或接收固定数量的字节 代码如下所示(我省略了发送部分,因为它与接收部分基本相同): 这似乎可行,但我不太喜欢这个解决方案。有更好的方法吗?也许有一种方法可以从内部访问AsyncResult对象DoFixedReceive?在Jeffrey Richter的

我试图使用Richter的
AsyncEnumerator
类实现APM模式。目标是实现一个
ExtendedSocket
类,该类派生自
Socket
,并提供
Begin/EndReceiveFixed
Begin/EndSendFixed
方法来异步发送或接收固定数量的字节

代码如下所示(我省略了发送部分,因为它与接收部分基本相同):


这似乎可行,但我不太喜欢这个解决方案。有更好的方法吗?也许有一种方法可以从内部访问
AsyncResult
对象
DoFixedReceive

在Jeffrey Richter的帮助下,我解决了我的问题():

不需要在迭代器中捕获所有异常并手动重新引用它们<代码>异步枚举器为我们执行此操作

但要小心调试器设置。我需要取消选中“常规调试”页面上的“仅启用我的代码”设置。否则,如果迭代器内发生异常,则调试器会在
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 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());
        }
    }
}
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;
    }
}