使用AsyncEnumerator实现APM模式时的异常处理 [英] Exception handling when implementing the APM pattern with AsyncEnumerator
问题描述
我正在尝试使用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模式时的异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!