return Task.FromException 的正确用法
Correct usage of 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,所以我有以下问题:
- 评论者在说什么?
- 审稿人是否正确?
- 为什么不 return 等待 Task.FromException?
- return await Task.FromException 的正确方案是什么?
审稿人完全正确。
您唯一会使用 Task.FromException
的情况是当您处于无法或不会使用 async
和 await
实现的方法中,并且您想要的结果是该任务应该是一个例外。
愚蠢的例子,但无论如何:
public Task<int> NotReallyAsync()
{
if (new Random().Next(2) == 0)
return Task.FromResult(42);
return Task.FromException<int>(new InvalidOperationException());
}
那么让我们一一解答您的问题:
评论者说 Task.FromException
应该只用于非 async
/await
方法,在 async
/await
方法,您应该重新抛出异常:
catch (Exception e)
{
Log.Logger.Error(e.ToString());
throw;
}
或者如果您实施异常过滤器:
catch (Exception e) when (Log.Logger.ExceptionFilter(e)) { }
是的,审稿人是正确的。
- 因为没必要,不如重新抛出异常。如果你想抛出异常,就抛出它。
async
/await
的目的是为了能够正常的写出你的方法,所以写一个正常的throw语句或者正常的catch-block.
- 非
async
/await
方法,仅此。
- 一般来说,return从 catch 中调用并不是好的编码习惯。
Task.FromException 通常在您希望在满足已知失败条件时依赖任务状态时使用。例如,如果一个对象是空的,你知道你应该 return 一个错误的 task.Client 可以使用错误的任务状态来显示适当的消息 user.I 修改代码只是为了告诉你例子.
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;
}
}
我最近观察到两个开发人员之间的代码审查。
提交了以下代码:
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,所以我有以下问题:
- 评论者在说什么?
- 审稿人是否正确?
- 为什么不 return 等待 Task.FromException?
- return await Task.FromException 的正确方案是什么?
审稿人完全正确。
您唯一会使用 Task.FromException
的情况是当您处于无法或不会使用 async
和 await
实现的方法中,并且您想要的结果是该任务应该是一个例外。
愚蠢的例子,但无论如何:
public Task<int> NotReallyAsync()
{
if (new Random().Next(2) == 0)
return Task.FromResult(42);
return Task.FromException<int>(new InvalidOperationException());
}
那么让我们一一解答您的问题:
评论者说
Task.FromException
应该只用于非async
/await
方法,在async
/await
方法,您应该重新抛出异常:catch (Exception e) { Log.Logger.Error(e.ToString()); throw; }
或者如果您实施异常过滤器:
catch (Exception e) when (Log.Logger.ExceptionFilter(e)) { }
是的,审稿人是正确的。
- 因为没必要,不如重新抛出异常。如果你想抛出异常,就抛出它。
async
/await
的目的是为了能够正常的写出你的方法,所以写一个正常的throw语句或者正常的catch-block. - 非
async
/await
方法,仅此。
- 一般来说,return从 catch 中调用并不是好的编码习惯。
Task.FromException 通常在您希望在满足已知失败条件时依赖任务状态时使用。例如,如果一个对象是空的,你知道你应该 return 一个错误的 task.Client 可以使用错误的任务状态来显示适当的消息 user.I 修改代码只是为了告诉你例子.
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; } }