Async method returning Task<T> with generic constraint in C#

和自甴很熟 提交于 2019-12-12 12:32:16

问题


I've implemented a command pattern in a project I'm working on. This is pretty much the current structure:

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);
    }
}

I want to handle any exceptions that could be thrown by the HttpClient, so I want to change CommandBase.ExecuteAsync to something like this...

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
    }
}

The compile error I get is "Cannot convert type Response to async return type T". I can't use T.CreateErrorResponse(), as outlined in this question.

How can I work around this?

Edit to downvoters: whether or not you agree with catching exceptions in a library like this, the question still stands!


回答1:


Although I am not sure this is the best solution (or feasible in your specific use case), what you can do is:

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;
    }
}

Usage:

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



回答2:


You can cast the response to T. EDIT: Added full source code

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
    }
}


来源:https://stackoverflow.com/questions/18562613/async-method-returning-taskt-with-generic-constraint-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!