我正在为客户端/服务器应用程序中的"客户端"类实现异步命令模式.我以前做过一些套接字编码,我喜欢他们在Socket/SocketAsyncEventArgs类中使用的新异步模式.
我的异步方法如下所示:public bool ExecuteAsync(Command cmd);
如果执行挂起则返回true,如果同步完成则返回false.我的问题是:即使出现异常,我是否应该始终调用回调(cmd.OnCompleted)?或者我应该从ExecuteAsync中抛出异常吗?
如果您需要,可以在这里找到更多细节.这类似于使用SocketAsyncEventArgs,但是我的类被称为SomeCmd而不是SocketAsyncEventArgs.
SomeCmd cmd = new SomeCmd(23, 14, 10, "hike!"); cmd.OnCompleted += this.SomeCmd_OnCompleted; this.ConnectionToServer.ExecuteAsync(cmd);
与Socket类一样,如果需要与回调方法(在本例中为SomeCmd_OnCompleted)进行协调,则可以使用ExecuteAsync的返回值来了解操作是否挂起(true)或操作是否同步完成.
SomeCmd cmd = new SomeCmd(23, 14, 10, "hike!"); cmd.OnCompleted += this.SomeCmd_OnCompleted; if( this.ConnectionToServer.ExecuteAsync(cmd) ) { Monitor.Wait( this.WillBePulsedBy_SomeCmd_OnCompleted ); }
这是我的基类的大大简化版本,但您可以看到它的工作原理:
class Connection { public bool ExecuteAsync(Command cmd) { /// CONSIDER: If you don't catch every exception here /// then every caller of this method must have 2 sets of /// exception handling: /// One in the handler of Command.OnCompleted and one where ExecuteAsync /// is called. try { /// Some possible exceptions here: /// 1) remote is disposed. happens when the other side disconnects (WCF). /// 2) I do something wrong in TrackCommand (a bug that I want to fix!) this.TrackCommand(cmd); remote.ServerExecuteAsync( cmd.GetRequest() ); return true; } catch(Exception ex) { /// Command completing synchronously. cmd.Completed(ex, true); return false; } } ///This is what gets called by some magic when the server returns a response. internal CommandExecuteReturn(CommandResponse response) { Command cmd = this.GetTrackedCommand(response.RequestId); /// Command completing asynchronously. cmd.Completed(response, false); } private IServer remote; } abstract class Command: EventArgs { internal void Completed(Exception ex, bool synchronously) { this.Exception = ex; this.CompletedSynchronously = synchronously; if( this.OnCompleted != null ) { this.OnCompleted(this); } } internal void Completed(CommandResponse response, bool synchronously) { this.Response = response; this.Completed(response.ExceptionFromServer, synchronously) } public bool CompletedSynchronously{ get; private set; } public event EventHandlerOnCompleted; public Exception Exception{ get; private set; } internal protected abstract CommandRequest GetRequest(); }
Nicholas Pia.. 5
.NET中异步操作的一种通用模式(至少对于BackgroundWorker
和BeginInvoke()/EndInvoke()
方法对是一个结果对象,它将回调与实际返回值或发生的任何异常分开.回调的责任是处理异常.
一些类似C#的伪代码:
private delegate int CommandDelegate(string number);
private void ExecuteCommandAsync()
{
CommandDelegate del = new CommandDelegate(BeginExecuteCommand);
del.BeginInvoke("four", new AsyncCallback(EndExecuteCommand), null);
}
private int BeginExecuteCommand(string number)
{
if (number == "five")
{
return 5;
}
else
{
throw new InvalidOperationException("I only understand the number five!");
}
}
private void EndExecuteCommand(IAsyncResult result)
{
CommandDelegate del;
int retVal;
del = (CommandDelegate)((AsyncResult)result).AsyncDelegate;
try
{
// Here's where we get the return value
retVal = del.EndInvoke(result);
}
catch (InvalidOperationException e)
{
// See, we had EndExecuteCommand called, but the exception
// from the Begin method got tossed here
}
}
所以如果你打电话ExecuteCommandAsync()
,它会立即返回.它BeginExecuteCommand()
是在一个单独的线程中启动的.如果它扔了一个异常,该异常不会抛出,直到你打电话EndInvoke()
的IAsyncResult
(你可以同时投射到AsyncResult
,这是证明,但如果转换让你不舒服,你可以通过它所处的状态.这样一来,异常处理代码"自然地"放置在与方法的返回值交互的位置.
有关更多信息,请查看有关MSDN上IAsyncResult模式的更多信息.
希望这可以帮助.
.NET中异步操作的一种通用模式(至少对于BackgroundWorker
和BeginInvoke()/EndInvoke()
方法对是一个结果对象,它将回调与实际返回值或发生的任何异常分开.回调的责任是处理异常.
一些类似C#的伪代码:
private delegate int CommandDelegate(string number);
private void ExecuteCommandAsync()
{
CommandDelegate del = new CommandDelegate(BeginExecuteCommand);
del.BeginInvoke("four", new AsyncCallback(EndExecuteCommand), null);
}
private int BeginExecuteCommand(string number)
{
if (number == "five")
{
return 5;
}
else
{
throw new InvalidOperationException("I only understand the number five!");
}
}
private void EndExecuteCommand(IAsyncResult result)
{
CommandDelegate del;
int retVal;
del = (CommandDelegate)((AsyncResult)result).AsyncDelegate;
try
{
// Here's where we get the return value
retVal = del.EndInvoke(result);
}
catch (InvalidOperationException e)
{
// See, we had EndExecuteCommand called, but the exception
// from the Begin method got tossed here
}
}
所以如果你打电话ExecuteCommandAsync()
,它会立即返回.它BeginExecuteCommand()
是在一个单独的线程中启动的.如果它扔了一个异常,该异常不会抛出,直到你打电话EndInvoke()
的IAsyncResult
(你可以同时投射到AsyncResult
,这是证明,但如果转换让你不舒服,你可以通过它所处的状态.这样一来,异常处理代码"自然地"放置在与方法的返回值交互的位置.
有关更多信息,请查看有关MSDN上IAsyncResult模式的更多信息.
希望这可以帮助.