【发布时间】:2022-01-10 10:21:57
【问题描述】:
根据 SonarQube 代码规则S4457 的要求,将异步方法包装在同步部分进行参数检查可能很快变得难以阅读。使用 C# 本地方法,可以省略本地方法的参数。
这种参数的省略对编译器和本地方法有什么缺点或问题吗?
public Task<MyResult> GetMyResultAsync(string myId, string someOption, CancellationToken cancellationToken)
{
// check arguments synchronously, before entering async context:
myId = myId ?? throw new ArgumentNullException(nameof(myId));
someOption = someOption ?? throw new ArgumentNullException(nameof(someOption));
return InnerAsync();
// don't replicate the arguments, use from outer method.
async Task<MyResult> InnerAsync()
{
using var httpClient = _httpClientFactory.CreateClient(CfgName);
var response = await httpClient.GetAsync(
CreateUrl(myId, someOption), cancellationToken)
.ConfigureAwait(false);
return ParseResponse<MyResult>(response);
}
}
相比:
public Task<MyResult> GetMyResultAsync(string myId, string someOption, CancellationToken cancellationToken)
{
// check arguments synchronously, before entering async context:
myId = myId ?? throw new ArgumentNullException(nameof(myId));
someOption = someOption ?? throw new ArgumentNullException(nameof(someOption));
return InnerAsync(myId, someOption, cancellationToken);
// new arguments for inner async method:
async Task<MyResult> InnerAsync(
string myIdInner, string someOptionInner,
CancellationToken cancellationTokenInner)
{
using var httpClient = _httpClientFactory.CreateClient(CfgName);
var response = await httpClient.GetAsync(
CreateUrl(myIdInner, someOptionInner),
cancellationTokenInner)
.ConfigureAwait(false);
return ParseResponse<MyResult>(response);
}
}
背景:规则要求参数检查,抛出Argument(Null/OutOfRange)Exception,在进入异步上下文之前同步发生,这样这些异常在发生火灾时不会丢失——然后忘记;它们甚至会在异步任务创建之前被抛出。这些方法仍被命名为“-Async”,因为它们在应用规则之前。
我知道异步方法基本上被编译成状态机,以局部变量作为属性,所以我不希望使用外部变量有任何缺点。对吗?
【问题讨论】:
-
See here。捕获 args 的版本稍微多一些工作,但在
async代码的上下文中它是非常微不足道的 -
您是在编写库还是应用程序代码的一部分?如果您不编写库,恕我直言,您可以忽略此规则。
-
它是公司库的一部分,包含各种 REST 客户端。我真的不喜欢这条规则,因为许多应用程序的编写方式都期望异步方法真正异步,包括参数检查。含义:火与忘记不应该扔;如果 AggregateException 被抛出(.Wait(), .Result),ArgumentException 也应该包含在其中。
-
@ErikHart:IMO,参数检查是一种boneheaded exception,永远不应该被抓住。因此,它们是否被包裹在
AggregateException中并不重要,它们是否被同步抛出也没关系。由于调用代码不应该捕获它们,因此它不应该对它们的抛出方式有任何期望。国际海事组织。 :)
标签: c# methods async-await arguments