0

在我的 NET 4.5 应用程序上,我有一个服务层。

我使用调度程序发送查询和接收回复:

示例:GetPostByIdQuery 由 GetPostByIdHandler 处理并返回 GetPostByIdReply。

如何更改我的代码以便以异步方式处理查询?

public class Dispatcher : IDispatcher {

  public TReply Send<TReply>(Query query) where TReply : Reply, new() {

    Type type = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TReply));

    IQueryHandler handler = (IQueryHandler)ObjectFactory.GetInstance(type);

    try {

      return (TReply)handler.Handle(query);

    } catch (Exception exception) {

      ILogger logger = ObjectFactory.GetInstance<ILogger>();
      logger.Send(exception);
      if (Debugger.IsAttached) throw;
      return new TReply { Exception = exception };

    }
  } // Send
}

更新:考虑到我添加的建议:

public interface IDispatcher {

  TReply Send<TReply>(Query query) where TReply : Reply, new();
  Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new();

} // IDispatcher

public class Dispatcher : IDispatcher {

  public TReply Send<TReply>(Query query) where TReply : Reply, new() {
  } // Send

  public Task<TReply> Send<TReply>(Query query) where TReply : Reply, new() {
  } // Send

}

两个问题:

  1. 我需要在两个 Send 方法中重复我的代码吗?或者一个可以打电话给另一个?

  2. 除了有两个发送方法,我可以有一个带有布尔“sendAsync”的方法吗?我不确定这是否有意义,因为返回类型是相同的......

4

2 回答 2

2

如果您想“拥抱异步”并从中获得任何真正的好处,您将需要修改IQueryHandler并使其异步,因为这是真正的工作正在完成的地方。

您从未向我们展示 IQueryHandler 的作用,但您可能需要编写新方法来真正支持异步代码

public class Dispatcher : IDispatcher {

  public TReply Send<TReply>(Query query) where TReply : Reply, new() {
       //(Snip) No changes to the original code
  } // Send

  public async Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new() {

    Type type = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TReply));

    IQueryHandler handler = (IQueryHandler)ObjectFactory.GetInstance(type);

    try {

      return await (TReply)handler.HandleAsync(query); //Uses the new method "Task<TResult> IQueryHandler<TQueryType, TResult>.HandleAsync(TQueryType query)"

    } catch (Exception exception) {

      ILogger logger = ObjectFactory.GetInstance<ILogger>();
      logger.Send(exception);
      if (Debugger.IsAttached) throw;
      return new TReply { Exception = exception };

    }
  } // Send
}

如果您不关心编写真正的异步代码的性能改进(更新所有IQueryHandlers 的成本可能不值得),但您仍然希望使用 async/await 来进行缓慢的过程,您可以轻松通过做包装

public class Dispatcher : IDispatcher {

  public TReply Send<TReply>(Query query) where TReply : Reply, new() {
      //(Snip) No changes to the original code
  } // Send

  public Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new() {
       return Task.Run(() => Send<TReply>(query));
  } // SendAsync
}

但是,就像我说的那样,不要期望从中获得太多性能提升,只是为了方便,这样您的调用者就不必自己做(也许在将来的某个时候,您可以用真正的异步代码替换它而无需更新任何使用此函数的调用者)。

于 2013-10-26T02:44:36.727 回答
0

您可以像这样添加一个新SendAsync方法:

public Task<TReply> SendAsync<TReply>(Query query) where TReply : Reply, new()
{
    return Task.Run(() =>
    {
        return Send<TReply>(query);
    });
}

要回答您的第二个问题,如果您只想公开一个方法签名,例如Send(Query query, bool sendAsync),并将您的原始Send方法设为私有,您可以编写如下内容:

public dynamic Send<TReply>(Query query, bool sendAsync) where TReply : Reply, new()
{
    if (sendAsync)
    {
        return Task.Run(() =>
        {
            return Send<TReply>(query);
        }
    }
    else
    {
        return Send<TReply>(query);
    }
}

类似地,Object调用者可以返回并拆箱。但是这样写很丑;我只是指出这是可能的。

于 2013-10-26T01:03:40.557 回答