Create rule S6603: Prefer using the collection-specific TrueForAll method instead of the All extension (#1782)
This commit is contained in:
parent
0ec4bbc964
commit
b264b60d7d
29
rules/S6603/csharp/code.adoc
Normal file
29
rules/S6603/csharp/code.adoc
Normal file
@ -0,0 +1,29 @@
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,csharp,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
public bool AreAllEven(List<int> data) =>
|
||||
data.All(x => x % 2 == 0);
|
||||
----
|
||||
|
||||
[source,csharp,diff-id=2,diff-type=noncompliant]
|
||||
----
|
||||
public bool AreAllEven(int[] data) =>
|
||||
data.All(x => x % 2 == 0);
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,csharp,diff-id=1,diff-type=compliant]
|
||||
----
|
||||
public bool AreAllEven(List<int> data) =>
|
||||
data.TrueForAll(x => x % 2 == 0);
|
||||
----
|
||||
|
||||
[source,csharp,diff-id=2,diff-type=compliant]
|
||||
----
|
||||
public bool AreAllEven(int[] data) =>
|
||||
Array.TrueForAll(data, x => x % 2 == 0);
|
||||
----
|
2
rules/S6603/csharp/metadata.json
Normal file
2
rules/S6603/csharp/metadata.json
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
9
rules/S6603/csharp/rule.adoc
Normal file
9
rules/S6603/csharp/rule.adoc
Normal file
@ -0,0 +1,9 @@
|
||||
include::../why-dotnet.adoc[]
|
||||
|
||||
include::../impact-dotnet.adoc[]
|
||||
|
||||
include::../how-dotnet.adoc[]
|
||||
|
||||
include::code.adoc[]
|
||||
|
||||
include::../resources-dotnet.adoc[]
|
3
rules/S6603/how-dotnet.adoc
Normal file
3
rules/S6603/how-dotnet.adoc
Normal file
@ -0,0 +1,3 @@
|
||||
== How to fix it
|
||||
|
||||
The `TrueForAll` method is defined on the collection class, and it has the same signature as the `All` extension method. The method can be replaced in place.
|
3
rules/S6603/impact-dotnet.adoc
Normal file
3
rules/S6603/impact-dotnet.adoc
Normal file
@ -0,0 +1,3 @@
|
||||
=== What is the potential impact?
|
||||
|
||||
We measured at least 4x improvement both in execution time. For more details see the `Benchmarks` section from the `More info` tab.
|
19
rules/S6603/metadata.json
Normal file
19
rules/S6603/metadata.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"title": "The collection-specific \"TrueForAll\" method should be used instead of the \"All\" extension",
|
||||
"type": "CODE_SMELL",
|
||||
"status": "ready",
|
||||
"remediation": {
|
||||
"func": "Constant\/Issue",
|
||||
"constantCost": "5min"
|
||||
},
|
||||
"tags": [
|
||||
"perfomance"
|
||||
],
|
||||
"defaultSeverity": "Minor",
|
||||
"ruleSpecification": "RSPEC-6603",
|
||||
"sqKey": "S6603",
|
||||
"scope": "All",
|
||||
"defaultQualityProfiles": ["Sonar way"],
|
||||
"quickfix": "targeted"
|
||||
}
|
||||
|
64
rules/S6603/resources-dotnet.adoc
Normal file
64
rules/S6603/resources-dotnet.adoc
Normal file
@ -0,0 +1,64 @@
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.trueforall[List<T>.TrueForAll(Predicate<T>)]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.array.trueforall[Array.TrueForAll<T>(T[\], Predicate<T>)]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablelist-1.trueforall[ImmutableList<T>.TrueForAll(Predicate<T>)]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablelist-1.builder.trueforall[ImmutableList<T>.Builder.TrueForAll(Predicate<T>)]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all[Enumerable.All<TSource>]
|
||||
|
||||
=== Benchmarks
|
||||
|
||||
[options="header"]
|
||||
|===
|
||||
| Method | Runtime | Mean | StdDev | Ratio | Allocated
|
||||
| TrueForAll | .NET 7.0 | 1.302 ms | 0.0027 ms | 0.21 | 1 B
|
||||
| All | .NET 7.0 | 6.279 ms | 0.0181 ms | 1.00 | 40004 B
|
||||
| TrueForAll | .NET Framework 4.6.2 | 1.105 ms | 0.0142 ms | 0.22 | -
|
||||
| All | .NET Framework 4.6.2 | 4.968 ms | 0.0143 ms | 1.00 | 40128 B
|
||||
|===
|
||||
|
||||
The results were generated by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet]:
|
||||
|
||||
[source,csharp]
|
||||
----
|
||||
private List<int> data;
|
||||
|
||||
[Params(10_000)]
|
||||
public int N { get; set; }
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup() =>
|
||||
data = Enumerable.Range(0, N).Select(x => 42).ToList();
|
||||
|
||||
[Benchmark]
|
||||
public void TrueForAll()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
_ = data.TrueForAll(x => x == 42); // List<T>.TrueForAll
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public void All()
|
||||
{
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
_ = data.All(x => x == 42); // Enumerable.All<TSource>
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Hardware configuration:
|
||||
|
||||
[source]
|
||||
----
|
||||
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update)
|
||||
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
|
||||
.NET SDK=7.0.203
|
||||
[Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
||||
.NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
||||
.NET Framework 4.6.2 : .NET Framework 4.8 (4.8.4614.0), X64 RyuJIT VectorSize=256
|
||||
----
|
33
rules/S6603/vbnet/code.adoc
Normal file
33
rules/S6603/vbnet/code.adoc
Normal file
@ -0,0 +1,33 @@
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,vbnet,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
Public Function AreAllEven(data As List(Of Integer)) As Boolean
|
||||
Return data.All(Function(x) x Mod 2 = 0)
|
||||
End Function
|
||||
----
|
||||
|
||||
[source,vbnet,diff-id=2,diff-type=noncompliant]
|
||||
----
|
||||
Public Function AreAllEven(data As Integer()) As Boolean
|
||||
Return data.All(Function(x) x Mod 2 = 0)
|
||||
End Function
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,vbnet,diff-id=1,diff-type=compliant]
|
||||
----
|
||||
Public Function AreAllEven(data As List(Of Integer)) As Boolean
|
||||
Return data.TrueForAll(Function(x) x Mod 2 = 0)
|
||||
End Function
|
||||
----
|
||||
|
||||
[source,vbnet,diff-id=2,diff-type=compliant]
|
||||
----
|
||||
Public Function AreAllEven(data As Integer()) As Boolean
|
||||
Return Array.TrueForAll(data, Function(x) x Mod 2 = 0)
|
||||
End Function
|
||||
----
|
2
rules/S6603/vbnet/metadata.json
Normal file
2
rules/S6603/vbnet/metadata.json
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
9
rules/S6603/vbnet/rule.adoc
Normal file
9
rules/S6603/vbnet/rule.adoc
Normal file
@ -0,0 +1,9 @@
|
||||
include::../why-dotnet.adoc[]
|
||||
|
||||
include::../impact-dotnet.adoc[]
|
||||
|
||||
include::../how-dotnet.adoc[]
|
||||
|
||||
include::code.adoc[]
|
||||
|
||||
include::../resources-dotnet.adoc[]
|
10
rules/S6603/why-dotnet.adoc
Normal file
10
rules/S6603/why-dotnet.adoc
Normal file
@ -0,0 +1,10 @@
|
||||
== Why is this an issue?
|
||||
|
||||
Both the `List.TrueForAll` method and the `IEnumerable.All` method can be used to check if all list elements satisfy a given condition in a collection. However, `List.TrueForAll` can be faster than `IEnumerable.All` for `List` objects. The performance difference may be minor for small collections, but for large collections, it can be noticeable.
|
||||
|
||||
*Applies to*
|
||||
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.trueforall[List]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.array.trueforall[Array]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablelist-1.trueforall[ImmutableList]
|
||||
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablelist-1.builder.trueforall[ImmutableList.Builder]
|
Loading…
x
Reference in New Issue
Block a user