在C#中使用generics约束返回Task 的异步方法

我在我正在研究的项目中实现了一个命令模式。 这几乎是当前的结构:

public class Response { public bool Success { get; private set; } public static Response CreateErrorResponse() { return new Response { Success = false }; } } public interface ICommand where T : Response { Task ExecuteAsync(); } public abstract CommandBase : ICommand where T: Response { protected abstract Uri BuildUrl(); protected abstract Task HandleResponseAsync(); public async override Task ExecuteAsync() { var url = BuildUrl(); var httpClient = new HttpClient(); var response = await httpClient.GetAsync(url); return await HandleResponseAsync(response); } } 

我想处理HttpClient可能引发的任何exception,所以我想将CommandBase.ExecuteAsync更改为这样的…

 public async override Task 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”。 我不能使用T.CreateErrorResponse() ,如本问题所述 。

我该如何解决这个问题?

编辑为downvoters:无论你是否同意在这样的图书馆中捕捉exception,问题仍然存在!

虽然我不确定这是最好的解决方案(或在您的特定用例中可行),但您可以做的是:

 public class Response { public bool Success { get; private set; } public ExceptionDispatchInfo ErrorInfo { get; private set; } public bool HasFailed { get { return !Success; } } public static T CreateErrorResponse(ExceptionDispatchInfo errorInfo) where T : Response, new() { var response = new T(); response.Success = false; response.ErrorInfo = errorInfo; return response; } } 

用法:

 catch (HttpRequestException hex) { return Response.CreateErrorResponse(ExceptionDispatchInfo.Capture(hex)); // should compile (I did not check) } 

您可以将响应转换为T. EDIT:添加完整的源代码

 public class Response { public bool Success { get; private set; } public static Response CreateErrorResponse() { return new Response { Success = false }; } } public interface ICommand where T : Response { Task ExecuteAsync(); } public abstract class CommandBase : ICommand where T: Response { protected abstract Uri BuildUrl(); protected abstract Task HandleResponseAsync(); public async Task ExecuteAsync() { var url = BuildUrl(); var httpClient = new System.Net.Http.HttpClient(); try { var response = await httpClient.GetAsync(url); return null;// await HandleResponseAsync(response); } catch (Exception hex) { return (T)Response.CreateErrorResponse(); // doesn't compile } } } public async override Task ExecuteAsync() { var url = BuildUrl(); var httpClient = new HttpClient(); try { var response = await httpClient.GetAsync(url); return await HandleResponseAsync(response); } catch (HttpRequestException hex) { return (T)Response.CreateErrorResponse(); // compiles on liqpad } }