【问题标题】:Correct usage of return Task.FromException正确使用 return Task.FromException
【发布时间】:2019-10-20 00:32:32
【问题描述】:

我最近观察到两个开发人员之间的代码审查。

以下代码已提交:

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

收到以下评论的cmets:

绝对不需要返回 await Task.FromException>(e),这是你在处理非等待任务时要做的事情。 在这种情况下,catch 将捕获任何异常 var response = await HttpClient.GetAsync(endpoint);会扔。 您应该删除它并按原样捕获异常

我不完全明白为什么不使用 Task.FromException 在这种情况下,所以我有以下问题:

  1. 审稿人在说什么?
  2. 审稿人是否正确?
  3. 为什么不返回 await Task.FromException?
  4. 返回 await Task.FromException 的正确方案是什么?

【问题讨论】:

  • 1.审阅者说你应该 throw; 代替(登录后) 2:是的,审阅者是正确的。 3/4。 Task.FromException 用于库代码中的非异步/等待方法
  • “非 async/await 方法”我的意思是一个不写成async Task 的方法,就像Task,在里面你必须返回任务,比如Task.FromResultTask.FromException .
  • @LasseVågsætherKarlsen 谢谢。我不明白您为什么要在非异步方法中使用。以及为什么您不会在 asyc 方法中使用。请您再详细解释一下吗?

标签: c# .net .net-4.0 task


【解决方案1】:
  1. 一般来说,从 catch 中返回并不是好的编码习惯。
  2. Task.FromException 通常用于当您希望在满足已知失败条件时依赖 Task 的状态时。例如,如果一个对象是空的,你知道你应该返回一个错误的任务。客户端可以使用任务的状态作为错误来向用户显示适当的消息。我修改了代码只是为了告诉你一个例子。

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

【讨论】:

    【解决方案2】:

    审稿人完全正确。

    您将使用Task.FromException 的唯一情况是,当您处于无法或不会使用asyncawait 实现的方法中,并且您希望任务的结果应该是异常时。

    愚蠢的例子,但无论如何:

    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-block。
    4. async/await 方法,仅此而已。

    【讨论】:

    • Task.FromResult 将抛出一个聚合异常,需要对其进行剖析以便进一步抛出。
    猜你喜欢
    • 2020-09-13
    • 2016-04-30
    • 1970-01-01
    • 2017-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    相关资源
    最近更新 更多