我在Java中遇到的大部分SonarLint规则似乎都是合理的。然而,自从我开始使用SonarLint的VB。. NET中,我遇到了一些规则,这些规则让我质疑它们的有用性,甚至质疑它们是否正确工作。
我想知道这是否只是我使用一些VB的问题。. NET以次优方式构建,或者该规则是否真的存在缺陷。(如果这个问题有点长,我很抱歉。我不知道我是否应该为每条单独的规则创建一个单独的问题。
我发现以下规则忽略了一些情况,这些情况实际上会出现误报:
-
S1871:相同条件结构中的两个分支不应该具有完全相同的实现
我发现这个给我带来了很多误报,因为有时检查条件的顺序确实很重要。以以下伪代码为例:If conditionA() Then doSomething() ElseIf conditionB() AndAlso conditionC() Then doSomethingElse() ElseIf conditionD() OrElse conditionE() Then doYetAnotherThing() '... feel free to have even more cases in between here Else Then doSomething() 'Non-compliant End If
如果我想遵循这个Sonar规则,并且仍然使代码以相同的方式运行,我必须将每个elseif条件的否定版本添加到第一个If条件。
另一个例子是下面的开关:Select Case i Case 0 To 40 value = 0 Case 41 To 60 value = 1 Case 61 To 80 value = 3 Case 81 To 100 value = 5 Case Else value = 0 'Non-compliant
在开关中使用最后一个case应该没有任何问题。的确,我可以事先将
value
初始化为0,并忽略最后一种情况,但这样我就多了一个不必要的赋值操作。Java规则集已经使我习惯于在每个开关中始终放置一个default
case。 -
S1764:不应该在二元操作符
的两边使用相同的表达式该规则似乎没有考虑到某些函数每次调用时可能返回不同的值,例如,在集合中访问一个元素将其从集合中删除:stack.Push(stack.Pop() / stack.Pop()) 'Non-compliant
我明白,如果这是一个太多的边缘情况,为它做特殊的例外。
以下规则我不太确定:
-
S3385: "Exit"语句不应该使用
虽然我同意Return
比Exit Sub
更具可读性,但使用单个Exit For
来打破For
或For Each
循环真的很糟糕吗?Java的SonarLint规则允许在将其标记为问题之前在循环中使用单个break;
。是否有一个原因,为什么默认在VB。NET在这方面更严格吗?或者该规则是否建立在这样的假设之上,即您可以使用LINQ扩展方法和lambda来解决几乎所有的循环问题? -
S2374:有符号类型应该优先于无符号类型
这条规则基本上表明,不应该使用无符号类型,因为它们"具有与有符号类型不同的算术运算符——很少有开发人员理解这些运算符"。在我的代码中,我只对ID值使用UInteger(因为我不需要负值,而且在我的情况下,Long会浪费内存)。它们存储在List(Of UInteger)中,并且只与其他UInteger进行比较。这条规则与我的情况相关吗(比较是规则提到的这些"算术运算符"的一部分吗),陷阱究竟是什么?如果不是,将该规则应用于涉及无符号类型的算术运算,而不是应用于它们的声明,岂不是更好? -
S2355:应该使用数组字面量来代替数组创建表达式
也许我不懂VB。NET很好,但我如何确切地满足这一规则,在以下情况下,我想创建一个固定大小的数组,其中初始化长度只在运行时知道?这是假阳性吗?Dim myObjects As Object() = New Object(someOtherList.Count - 3) {} 'Non-compliant
当然,我可以使用List(Of Object)。但我还是很好奇
谢谢你提出这些观点。请注意,并非所有规则每次都适用。有些情况下,我们需要在假阳性/假阴性/真实情况之间取得平衡。例如,在操作符规则的两边使用相同的表达式。有相同的操作数是一个bug吗?不,不是的。如果是,编译器就会报告它。是难闻的气味,还是通常是错误的?是的,在很多情况下。以罗斯林为例。我们是否应该调整该规则以排除某些情况?是的,我们应该,2 << 2
没有任何问题。因此,需要进行很多平衡,我们试图满足于为用户带来最大价值的实现。
对于您提出的要点:
- 相同条件结构中的两个分支不应该有完全相同的实现
该规则通常指出,两个代码块完全匹配是一个不好的迹象。由于许多原因,应该避免复制粘贴代码,例如,如果您需要在一个地方修复代码,那么您也需要在另一个地方修复它。添加否定条件会造成混乱,这一点您是对的,但是如果您将每个条件提取到它自己的方法中(并使用适当的名称调用其中的否定方法),那么它可能会提高代码的可读性。
对于Select Case
,同样,复制粘贴的代码总是一个不好的信号。在本例中,您可以这样做:
Select Case i
...
Case 0 To 40
Case Else
value = 0 ' Compliant
End Select
或者直接去掉0-40的大小写
- 不应该在二元操作符 的两边使用相同的表达式
我认为这是一个极端情况。见答案的第一段。
- 不应该使用"Exit"语句
选择另一种类型的循环,或者改变停止条件,几乎总是正确的,你可以不使用任何"退出"语句。在循环中设置一个单独的退出点是很好的做法。
- 有符号的类型应该优先于无符号的
这是SonarQube VB的遗留规则。我同意你的观点,它不应该在SonarLint中默认启用。我在JIRA中创建了以下票据:https://jira.sonarsource.com/browse/SLVS-1074
- 应该使用数组字面量代替数组创建表达式
是的,这似乎是一个假阳性,当显式指定大小时,我们不应该报告数组创建。https://jira.sonarsource.com/browse/slvs - 1075