代码优化 - 删除这个总是评估为“真”的表达式

Posted

技术标签:

【中文标题】代码优化 - 删除这个总是评估为“真”的表达式【英文标题】:Code Optimisation - remove this expression which always evaluates to "true" 【发布时间】:2021-06-03 20:40:15 【问题描述】:

我正在尝试使用 SonarQube 优化代码

List<string> itemList = serviceObject.GetItems();

我尝试使用以下代码验证列表

if(itemList != null && itemList.Any()

     //Some operations

执行上述代码时,我收到 Sonarqube 错误 删除此表达式,该表达式的计算结果始终为“true” 所以我将代码重构为

if(itemList == null || !itemList.Any())
    return;
//Some Operations

执行上述代码时,我收到 Sonarqube 错误 删除此表达式,该表达式的计算结果始终为“false”

谁能告诉我这里出了什么问题?

【问题讨论】:

您是否尝试将= serviceObject.GetItems() 替换为= null,看看会发生什么。也许.GetItems() 方法中的某些东西确保它不为空?但这似乎是一个奇怪的警告。 能否贴出完整的代码。 @JakobBuskSørensen 除非启用可空引用类型,在这种情况下 itemList 不能为空。 您使用的是哪个 C# 版本?您是否通过在文件中添加#nullable enable 或在csproj 文件中添加&lt;Nullable&gt;enable&lt;/Nullable&gt; 来启用可空引用类型? serviceObject.GetItems() 返回什么类型? .错误意味着 itemList 始终为空 【参考方案1】:

您可以将其缩短为

if (itemList?.Count >0)

...

if (itemList?.Any() ==true)

...

?. 是Null conditional operators 之一(另一个是?[]),简称Elvis operator,它允许您访问潜在的空变量而无需抛出。 Elvis 运算符之后的整个表达式的结果可以为 null,如果变量为 null,则返回 null

这意味着itemList?.Count 返回一个Nullable&lt;int&gt;,而itemList?.Any() 返回一个Nullable&lt;bool&gt;Nullable&lt;T&gt; 定义了自身与其基类型 T 之间的关系运算符,但不能在没有显式转换的情况下用作 T。这就是需要(itemList?.Any() ==true) 的原因。

如果你使用Nullable Reference Types,itemList 不能为空,所以一个简单的比较就足够了:

if (itemList.Count >0)

...

如果通过在源文件中设置#nullable enable 或在csproj 文件中设置&lt;Nullable&gt;enable&lt;/Nullable&gt; 来启用可空引用类型,编译器会确保所有返回引用类型的变量、字段和方法不是 em> null,迫使您要么解决问题,要么明确指定一个变量可以为空。

启用 NRT 后,此行:

List<string> itemList = serviceObject.GetItems();

如果GetItems 从未返回空值,则只会在没有警告的情况下编译。如果编译器对此表示怀疑,它会发出警告,建议您修复问题或明确声明 itemList 可以为空:

List<string>? itemList = serviceObject.GetItems();

【讨论】:

我也有同样的想法,但没有实现,因为我认为它只处理 True case 并且可能导致 SonarQube 代码异味。令我惊讶的是,它通过了 SonarQube。吸取教训而不是思考它会不会起作用,最好尝试一下并得出结论。非常感谢【参考方案2】:

我相信这是由于空比较。

itemList != null

serviceObject.GetItems(); 很有可能通过 [NotNull] 注释保证不返回 null。因此,空检查是多余的。

How can I show that a method will never return null (Design by contract) in C#

【讨论】:

C# 中的NotNull 属性与或多或少被放弃的代码契约关系不大。当它无法确定结果或值的可空性时,它与 NRT 一起用于help the compiler。在这种情况下,对于 NRT,List&lt;string&gt; 表示变量不能为空。如果GetItems 返回List&lt;string&gt;?,编译器将生成警告 NotNull 是更清晰的东西,而不是 C# 的东西(不再),对吧? @PanagiotisKanavos 是的,您对可空引用类型是正确的,我给出的解释具有误导性。【参考方案3】:

if( itemList !=null ) //做某事...

【讨论】:

表达式检查 1 个或多个项目,而不仅仅是 null @Panagiotis Kanavos 如果您知道,请发布正确的答案。 我在 20 分钟前做过,解释了发生了什么以及如何缩短表达式 @Panagiotis Kanavos 我有疑问,但没有人回答我...如果我找到了帮助...对我来说很容易【参考方案4】:
List<string> itemList = new List<string>();
itemList = serviceObject.GetItems();
if(itemList!=null && itemList.Count() > 0 )

     //Some operations

Count 足以验证列表

List 永远不会为 null,但不会有任何元素。但是您必须将其实例化,以免引发异常。

【讨论】:

你不能调用任何方法(比如Count(),如果列表没有被实例化,即如果它是null)。因此,要使用Count()Any(),您必须首先确保列表不为空。 @JKC Jakob 说的是对的。我们不能指望服务不返回 null。最好检查 null 小心 Count();在某些情况下,这可能是性能灾难;见***.com/questions/305092/… Jakob 的重点是“你怎么能绝对确定 serviceObject.GetItems() 没有返回 null?” - 如果是这样,你的代码就会爆炸。您的编辑并没有以任何方式解决这个问题,它只是让不正确的答案变得更糟 @JKC 这根本不是我要说的重点。以下是您的代码爆炸的方式:dotnetfiddle.net/JX5NzGdotnetfiddle.net/prqKJqdotnetfiddle.net/ydpvCo,即使在修复了您的代码无法编译的错误之后,因为 Count 是列表的属性,而不是方法(您的小提琴没有导入林克)。创建一个新列表只是用 GetItems 的返回值覆盖它是没有意义的,即使你做了itemList = service.GetItems()?itemList; 它也会仍然爆炸,因为新列表在 [0 处没有项目]

以上是关于代码优化 - 删除这个总是评估为“真”的表达式的主要内容,如果未能解决你的问题,请参考以下文章

声纳 更改此条件,使其不总是评估为“真”。假阳性

Visual Studio 2010 中的“无法评估表达式,因为当前方法的代码已优化”

无法评估表达式,因为代码已优化或本机框架位于调用堆栈顶部

3500N - DAG优化(编译原理)

正则表达式未按预期进行评估

“更改此条件,使其不会总是评估为假” - SonarQube