本文介绍了使用AsyncEnumerator实现APM模式时的异常处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to implement the APM pattern using Richter's AsyncEnumerator class. The goal is to implement an ExtendedSocket class which is derived from Socket and offers Begin/EndReceiveFixed and Begin/EndSendFixed methods to send or receive a fixed amount of bytes asynchronously.

代码看起来像这样(我省略了发送部分,因为它与接收部分基本相同)

The code looks like this (I omitted the sending part since it is basically the same as for receiving):

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 中处理异常.我想实现默认的APM行为,其中在调用 EndReceiveFixed 时抛出(重新)异常.

This works perfectly fine in my application but I don't know how to handle exceptions in DoReceiveFixed. I'd like to implement the default APM behaviour where exceptions are (re)thrown when EndReceiveFixed is called.

不幸的是,我无法访问 DoReceiveFixed 中的 AsyncResult 对象,因此我无法调用 SetAsCompleted 上的异常 AsyncResult 对象.

Unfortunately I don't have access to the AsyncResult object inside DoReceiveFixed, so I can't call SetAsCompleted with an exception on the AsyncResult object.

我当前的解决方法是使用 AsyncEnumerator< Exception> 而不是 AsyncEnumerator 这样:

My current workaround is to use AsyncEnumerator<Exception> instead of AsyncEnumerator like this:

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 对象?

This seems to work but I don't really like this solution. Is there a better way to do this? Maybe there is a way to get access to the AsyncResult object from inside DoFixedReceive?

推荐答案

在杰弗里·里希特(Jeffrey Richter)的帮助下,我解决了我的问题(请参阅此处):

With the help of Jeffrey Richter I solved my problem (see here):

没有必要在迭代器中捕获所有异常并手动将其重新抛出. AsyncEnumerator 为我们做到了.

There is no need to catch all exceptions in an iterator and rethrow them manually. AsyncEnumerator does this for us.

但是请注意您的调试器设置.我需要在常规调试页面上取消选中仅启用我的代码"设置.否则,如果迭代器内部发生异常,调试器会在 AsyncEnumerator 有机会捕获异常之前,以未处理的异常消息中断.

But be careful with your debugger settings. I needed to uncheck the 'Enable Just My Code' setting on the general debugging page. Otherwise, if an exception occurs inside the iterator, the debugger breaks with an unhandled exception message before AsyncEnumerator has the chance to catch the exception.

这篇关于使用AsyncEnumerator实现APM模式时的异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 08:19