【发布时间】:2013-09-04 22:28:54
【问题描述】:
我在a project I'm working on 中实现了一个命令模式。这几乎是当前的结构:
public class Response
{
public bool Success { get; private set; }
public static Response CreateErrorResponse()
{
return new Response { Success = false };
}
}
public interface ICommand<T> where T : Response
{
Task<T> ExecuteAsync();
}
public abstract CommandBase : ICommand<T> where T: Response
{
protected abstract Uri BuildUrl();
protected abstract Task<T> HandleResponseAsync();
public async override Task<T> ExecuteAsync()
{
var url = BuildUrl();
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
return await HandleResponseAsync(response);
}
}
我想处理 HttpClient 可能抛出的任何异常,所以我想将 CommandBase.ExecuteAsync 更改为类似这样的内容...
public async override Task<T> ExecuteAsync()
{
var url = BuildUrl();
var httpClient = new HttpClient();
try
{
var response = await httpClient.GetAsync(url);
return await HandleResponseAsync(response);
}
catch (HttpRequestException hex)
{
return Response.CreateErrorResponse(); // doesn't compile
}
}
我得到的编译错误是“无法将类型响应转换为异步返回类型 T”。如in this question 所述,我不能使用T.CreateErrorResponse()。
我该如何解决这个问题?
编辑反对票:无论您是否同意在这样的库中捕获异常,问题仍然存在!
【问题讨论】:
-
CreateErrorResponse()的类型为IResponse,但应为Response。 -
这背后的想法是什么?你可以让它抛出异常,它会自动聚合到等待者。
-
@ClausJørgensen 是的。但是在这种特定情况下,IMO 将 HttpRequestExceptions 与库正在包装的 API 上的错误相同对待更为简洁,因为调用可能由于其他原因(服务过载、404 等)而失败。如果消费者想要异常,我将添加一个标志来禁用/启用该行为。
-
然后包装异常。你不应该像这样包装异常,这是一个非常糟糕的 API 设计。使用任务时,您可以显式检查 .Error 属性以在异常失败时获取异常。您通过像这样包装它来防止消费者正确使用任务。
-
我理解您的理由 - 关注点分离,单一职责 - 但我正在开发一个与我的库并行的应用程序。与我的图书馆一起工作,我发现自己想要这个作为一种选择。客户端代码已经检查了从库返回的 Response 对象的 Success 属性,因此不需要到处都需要 try/catch 代码会更整洁。这也是我打算这样做的唯一情况。提到 Tasks 的 Error 属性是什么意思?
标签: c# generics async-await command-pattern