Обработка исключений при реализации шаблона APM с AsyncEnumerator - PullRequest
0 голосов
/ 19 августа 2011

Я пытаюсь реализовать шаблон APM, используя класс AsyncEnumerator Рихтера.Цель состоит в том, чтобы реализовать класс ExtendedSocket, производный от Socket и предлагающий методы Begin/EndReceiveFixed и Begin/EndSendFixed для асинхронной отправки или получения фиксированного количества байтов.

Код выглядит следующим образом (Я пропустил отправляющую часть, так как она в основном такая же, как для получения):

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.

К сожалению, у меня нет доступа к объекту AsyncResult внутри DoReceiveFixed, поэтому яя не могу вызвать 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;
    }
}

ThisКажется, работает, но мне не очень нравится это решение.Есть лучший способ сделать это?Может быть, есть способ получить доступ к объекту AsyncResult изнутри DoFixedReceive?

1 Ответ

0 голосов
/ 07 сентября 2011

С помощью Джеффри Рихтера я решил свою проблему ( см. Здесь ):

Нет необходимости перехватывать все исключения в итераторе и перебрасывать их вручную. AsyncEnumerator делает это для нас.

Но будьте осторожны с настройками отладчика. Мне нужно было снять флажок «Включить только мой код» на странице общей отладки. В противном случае, если в итераторе возникает исключение, отладчик прерывается с необработанным сообщением об исключении, прежде чем AsyncEnumerator сможет его перехватить.

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