当前位置:  开发笔记 > 编程语言 > 正文

异步命令模式 - 异常处理

如何解决《异步命令模式-异常处理》经验,为你挑选了1个好方法。

我正在为客户端/服务器应用程序中的"客户端"类实现异步命令模式.我以前做过一些套接字编码,我喜欢他们在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 EventHandler OnCompleted;

    public Exception Exception{ get; private set; }

    internal protected abstract CommandRequest GetRequest();
}

Nicholas Pia.. 5

.NET中异步操作的一种通用模式(至少对于BackgroundWorkerBeginInvoke()/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模式的更多信息.

希望这可以帮助.



1> Nicholas Pia..:

.NET中异步操作的一种通用模式(至少对于BackgroundWorkerBeginInvoke()/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模式的更多信息.

希望这可以帮助.

推荐阅读
虎仔球妈_459
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有