Правильное использование return Task.FromException

Недавно я наблюдал обзор кода между двумя разработчиками.

Был отправлен следующий код:

 public async Task<List<Thing>> GetThings()
    {
        try
        {
            var endpoint = $"{Settings.ThingEndpoint}/things";
            var response = await HttpClient.GetAsync(endpoint);
            return JsonConvert.DeserializeObject<List<Thing>>(await response.Content.ReadAsStringAsync());
        }
        catch (Exception e)
        {
            Log.Logger.Error(e.ToString());
            return await Task.FromException<List<Thing>>(e);
        }
    }

Который получил следующие комментарии обзора:

There is absolutely no need to return await Task.FromException>(e), this is something you do when dealing with non awaited task. In this case the catch will capture whatever exception var response = await HttpClient.GetAsync(endpoint); will throw. You should just remove it and catch the exception as is

Я не совсем понимаю, почему бы не использовать Task.FromException в этом случае, поэтому у меня есть следующие вопросы:

  1. Что говорит рецензент?
  2. Прав ли рецензент?
  3. Почему бы не вернуть await Task.FromException?
  4. Каков правильный сценарий возврата await Task.FromException?

1. Рецензент говорит, что вы должны throw; вместо этого (после регистрации) 2: Да, рецензент прав. 3/4. Task.FromException предназначен для использования в коде библиотеки в неасинхронных/ожидающих методах.

Lasse V. Karlsen 04.06.2019 15:07

Под «методом без асинхронности/ожидания» я подразумеваю метод, который написан не как async Task, а как Task, внутри которого вы должны возвращать задачи, например Task.FromResult или Task.FromException.

Lasse V. Karlsen 04.06.2019 15:08

@LasseVågsætherKarlsen Спасибо. Я не понимаю, почему вы используете неасинхронный метод. А почему бы вам не использовать в asyc методе. Можете ли вы объяснить подробнее, пожалуйста?

fourbeatcoder 04.06.2019 15:12
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
14
3
6 106
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Рецензент совершенно прав.

Единственная ситуация, которую вы бы использовали Task.FromException, — это когда вы находитесь в методе, который вы не можете или не будете реализовывать с помощью async и await, и вы хотите, чтобы результат задачи был исключением.

Идиотский пример, но тем не менее:

public Task<int> NotReallyAsync()
{
    if (new Random().Next(2) == 0)
        return Task.FromResult(42);

    return Task.FromException<int>(new InvalidOperationException());
}

Итак, давайте разберемся с вашими вопросами один за другим:

  1. Рецензент говорит, что Task.FromException следует использовать только в методе, отличном от async/await, в методе async/await вместо этого вы должны просто повторно выдать исключение:

    catch (Exception e)
    {
        Log.Logger.Error(e.ToString());
        throw;
    }
    

    или если вы реализуете фильтр исключений:

    catch (Exception e) when (Log.Logger.ExceptionFilter(e)) { }
    
  2. Да, рецензент прав.

  3. Поскольку в этом нет необходимости, вместо этого просто повторно создайте исключение. Если вы хотите сгенерировать исключение, просто сгенерируйте его. Цель async/await состоит в том, чтобы иметь возможность написать свой метод обычным образом, поэтому напишите обычный оператор throw или обычный блок catch.
  4. Не-async/await методы, да и только.

Task.FromResult выдаст совокупное исключение, которое необходимо проанализировать для дальнейшего повторного генерирования.

TRS 04.06.2019 17:12
  1. Как правило, возврат из catch не является хорошей практикой кодирования.
  2. Task.FromException обычно используется, когда вы хотите полагаться на состояние задачи, если выполняется известное условие сбоя. Например, если объект имеет значение null, вы знаете, что должны вернуть задачу с ошибкой. Клиент может использовать состояние задачи как неисправной, чтобы показать пользователю соответствующее сообщение. Я изменил код только для того, чтобы рассказать вам на примере.

         public async Task<List<Thing>> GetThings()
        {
            try
            {
                var endpoint = $"{Settings.ThingEndpoint}/things";
                var response = await HttpClient.GetAsync(endpoint);
                var obj = JsonConvert.DeserializeObject<List<Thing>>(await response.Content.ReadAsStringAsync());
                if (obj==null)
                {
                  return await Task.FromException<List<Thing>>(new NullRefernceException());
                }
                else
                {     
    
                }
    
            }
            catch (Exception e)
            {
                Log.Logger.Error(e.ToString());
                throw;
    
            }
        }
    

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