2013-09-01 5 views
3

Я реализовал шаблон команды в a project I'm working on. Это в значительной степени текущая структура:Асинхронный метод, возвращающий задачу <T> с общим ограничением в C#

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

Ошибка компиляции, которую я получаю: «Невозможно преобразовать тип Response to async return type T». Я не могу использовать T.CreateErrorResponse(), как указано in this question.

Как я могу обойти это?

Редактировать нижестоящие элементы: согласны ли вы с улавливанием исключений в библиотеке, подобной этому, вопрос все еще стоит!

+2

Параметр 'CreateErrorResponse()' имеет Ty pe 'IResponse', но ожидаемый' Response'. –

+0

@ Hamlet Typo! Исправлена. – rikkit

+0

Какова идея этого? Вы могли бы просто позволить этому генерировать исключение, и оно будет автоматически объединено с awaiter. –

ответ

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

Вы можете кастовал ответ Т. EDIT: Добавлен полный исходный код

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

Но экземпляр, который вы возвращаете, - это * не * a 'T'. То есть теперь это приведет к ошибке выполнения ('InvalidCastException'), даже если она компилируется. Я сомневаюсь, что это приемлемое решение. – Alex

+0

CreateErrorResponse() возвращает Response и T вытекает из Response - для этого для работы T необходимо объявить ковариантным. Тип Task не является ковариантным, хотя это будет работать, если мне не нужен асинхронный. – rikkit