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