异步方法在C#</t>中返回带有泛型约束的Task <t>

时间:2013-09-01 20:31:53

标签: c# generics async-await command-pattern

我在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”。我无法使用T.CreateErrorResponse(),如in this question所述。

我该如何解决这个问题?

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

2 个答案:

答案 0 :(得分:3)

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

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<T>(ExceptionDispatchInfo errorInfo) where T : Response, new()
    {
        var response = new T();
        response.Success = false;
        response.ErrorInfo = errorInfo;
        return response;
    }
}

用法:

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

答案 1 :(得分:0)

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

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 class CommandBase<T> : ICommand<T> where T: Response
{
    protected abstract Uri BuildUrl();
    protected abstract Task<T> HandleResponseAsync();

    public async Task<T> 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<T> 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
    }
}