Асинхронная операция, возвращающая результат с наследованием метода

У меня простой вопрос об асинхронных операциях. У меня есть класс композиции, используемый для инкапсуляции экземпляра HttpClient. Этот класс имеет абстрактный базовый класс, чтобы избежать избыточности кода.

Моя проблема возникает, когда я пытаюсь переопределить базовый метод, выполняющий часть работы в производном методе, который выполняет дополнительные операции.

Чтобы было понятнее, у меня есть:

Базовый метод:

    /// <summary>
    /// Execute a Typed GET Request and returning <typeparamref name = "TResponse"/> result.
    /// </summary>
    /// <typeparam name = "TResponse">Response specified type.</typeparam>
    /// <param name = "route">Uri string to request.</param>
    /// <param name = "path">Path parameters to provide to the <paramref name = "route"/>.</param>
    /// <param name = "query">Query parameters to provide to the <paramref name = "route"/>.</param>
    /// <returns>The <see cref = "Task"/> that represents the asynchronous operation containing <typeparamref name = "TResponse"/> response object.</returns>
    /// <exception cref = "HttpRequestException">Raised if the Http request failed.</exception>
    public virtual async Task<TResponse?> GetAsync<TResponse>(string route, Dictionary<string, string>? path = null, Dictionary<string, string>? query = null)
    {
        using HttpResponseMessage response = await _httpClient.GetAsync(BuildUri(route, path, query));
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<TResponse>(new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
    }

Производный метод:

    /// <inheritdoc/>
    public override async Task<TResponse?> GetAsync<TResponse>(string route, Dictionary<string, string>? path = null, Dictionary<string, string>? query = null)
    {
        var token = await GetBearerToken();
        base._httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return base.GetAsync<TResponse>(route, path, query);
    }

Таким образом, метод базового класса несет ответственность за http-запрос, а производный метод добавляет дополнительные предварительные обработки для настройки httpClient с необходимыми заголовками и другими. Ошибка возникает при возврате, я пробовал оба:

return base.GetAsync<TResponse>(route, path, query);

с ошибкой: Невозможно преобразовать тип Task<TResponse?> в TResponse?

и

return await base.GetAsync<TResponse>(route, path, query);

с ошибкой: Невозможно преобразовать тип TResponse в TResponse?

Я не понимаю, почему, когда я жду результата, выполняется приведение Nullable<TResponse> к TResponse в производном методе, зная тот факт, что базовый метод возвращает Task<TResponse?>.

Заранее спасибо.

Редактировать:

@Selvin и @Enigmativity получили здесь правильный ответ, добавив ограничение класса к общему TResponse типу в определении метода как базового, так и производного метода, чтобы решить проблему, спасибо за вашу помощь!

Возможно, вам нужно добавить ограничение к общему параметру, которое заставит аргумент быть ссылочным типом.

Selvin 18.01.2023 12:07

или просто используйте Task<TResponse> GetAsync<TResponse>() и пусть пользователь решит использовать GetAsync<Type>() или GetAsync<Type?>()

Selvin 18.01.2023 12:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш метод должен ограничить TResponse значением class:

public virtual async Task<TResponse?> GetAsync<TResponse>(
        string route,
        Dictionary<string, string>? path = null,
        Dictionary<string, string>? query = null)
    where TResponse : class

Другие вопросы по теме