Я пытаюсь реализовать шаблон 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
?