
org.sonar.plugins.csharp.S6603.html Maven / Gradle / Ivy
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.
It is important to enable this rule with caution, as performance outcomes can vary significantly across different runtimes. Notably, the performance improvements in .NET 9 have brought
All
closer to the performance of collection-specific TrueForAll
methods in most scenarios.
Applies to
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.
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.
Code examples
Noncompliant code example
public bool AreAllEven(List<int> data) =>
data.All(x => x % 2 == 0);
public bool AreAllEven(int[] data) =>
data.All(x => x % 2 == 0);
Compliant solution
public bool AreAllEven(List<int> data) =>
data.TrueForAll(x => x % 2 == 0);
public bool AreAllEven(int[] data) =>
Array.TrueForAll(data, x => x % 2 == 0);
Resources
Documentation
- Microsoft Learn - List<T>.TrueForAll(Predicate<T>)
- Microsoft Learn - Array.TrueForAll<T>(T[],
Predicate<T>)
- Microsoft Learn - ImmutableList<T>.TrueForAll(Predicate<T>)
- Microsoft Learn - ImmutableList<T>.Builder.TrueForAll(Predicate<T>)
- Microsoft Learn - Enumerable.All<TSource>
Benchmarks
Method
Runtime
Categories
Mean
Standard Deviation
Allocated
ArrayAll
.NET 8.0
Array
109.25 μs
1.767 μs
32 B
ArrayTrueForAll
.NET 8.0
Array
45.01 μs
0.547 μs
-
ArrayAll
.NET 9.0
Array
22.28 μs
0.254 μs
-
ArrayTrueForAll
.NET 9.0
Array
37.60 μs
0.382 μs
-
ArrayAll
.NET Framework 4.8.1
Array
495.90 μs
4.342 μs
40 B
ArrayTrueForAll
.NET Framework 4.8.1
Array
164.52 μs
2.030 μs
-
ImmutableListAll
.NET 8.0
ImmutableList<T>
940.29 μs
5.600 μs
72 B
ImmutableListTrueForAll
.NET 8.0
ImmutableList<T>
679.46 μs
2.371 μs
-
ImmutableListAll
.NET 9.0
ImmutableList<T>
922.43 μs
14.564 μs
72 B
ImmutableListTrueForAll
.NET 9.0
ImmutableList<T>
692.31 μs
8.897 μs
-
ImmutableListAll
.NET Framework 4.8.1
ImmutableList<T>
4,578.72 μs
77.920 μs
128 B
ImmutableListTrueForAll
.NET Framework 4.8.1
ImmutableList<T>
4,393.49 μs
122.061 μs
-
ImmutableListBuilderAll
.NET 8.0
ImmutableList<T>.Builder
970.45 μs
13.598 μs
73 B
ImmutableListBuilderTrueForAll
.NET 8.0
ImmutableList<T>.Builder
687.82 μs
6.142 μs
-
ImmutableListBuilderAll
.NET 9.0
ImmutableList<T>.Builder
981.17 μs
12.966 μs
72 B
ImmutableListBuilderTrueForAll
.NET 9.0
ImmutableList<T>.Builder
710.19 μs
16.195 μs
-
ImmutableListBuilderAll
.NET Framework 4.8.1
ImmutableList<T>.Builder
4,780.50 μs
43.282 μs
128 B
ImmutableListBuilderTrueForAll
.NET Framework 4.8.1
ImmutableList<T>.Builder
4,493.82 μs
76.530 μs
-
ListAll
.NET 8.0
List<T>
151.12 μs
2.028 μs
40 B
ListTrueForAll
.NET 8.0
List<T>
58.03 μs
0.493 μs
-
ListAll
.NET 9.0
List<T>
22.14 μs
0.327 μs
-
ListTrueForAll
.NET 9.0
List<T>
46.01 μs
0.327 μs
-
ListAll
.NET Framework 4.8.1
List<T>
619.86 μs
6.037 μs
48 B
ListTrueForAll
.NET Framework 4.8.1
List<T>
208.49 μs
2.340 μs
-
Glossary
The results were generated by running the following snippet with BenchmarkDotNet:
// Explicitly cache the delegates to avoid allocations inside the benchmark.
private readonly static Func<int, bool> ConditionFunc = static x => x == Math.Abs(x);
private readonly static Predicate<int> ConditionPredicate = static x => x == Math.Abs(x);
private List<int> list;
private ImmutableList<int> immutableList;
private ImmutableList<int>.Builder immutableListBuilder;
private int[] array;
[Params(100_000)]
public int N { get; set; }
[GlobalSetup]
public void GlobalSetup()
{
list = Enumerable.Range(0, N).Select(x => N - x).ToList();
immutableList = ImmutableList.CreateRange(list);
immutableListBuilder = ImmutableList.CreateBuilder<int>();
immutableListBuilder.AddRange(list);
array = list.ToArray();
}
[BenchmarkCategory("List<T>"), Benchmark]
public bool ListAll() =>
list.All(ConditionFunc);
[BenchmarkCategory("List<T>"), Benchmark(Baseline = true)]
public bool ListTrueForAll() =>
list.TrueForAll(ConditionPredicate);
[BenchmarkCategory("ImmutableList<T>"), Benchmark(Baseline = true)]
public bool ImmutableListAll() =>
immutableList.All(ConditionFunc);
[BenchmarkCategory("ImmutableList<T>"), Benchmark]
public bool ImmutableListTrueForAll() =>
immutableList.TrueForAll(ConditionPredicate);
[BenchmarkCategory("ImmutableList<T>.Builder"), Benchmark(Baseline = true)]
public bool ImmutableListBuilderAll() =>
immutableListBuilder.All(ConditionFunc);
[BenchmarkCategory("ImmutableList<T>.Builder"), Benchmark]
public bool ImmutableListBuilderTrueForAll() =>
immutableListBuilder.TrueForAll(ConditionPredicate);
[BenchmarkCategory("Array"), Benchmark(Baseline = true)]
public bool ArrayAll() =>
array.All(ConditionFunc);
[BenchmarkCategory("Array"), Benchmark]
public bool ArrayTrueForAll() =>
Array.TrueForAll(array, ConditionPredicate);
Hardware configuration:
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9277.0), X64 RyuJIT VectorSize=256
.NET 8.0 : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 9.0 : .NET 9.0.0 (9.0.24.47305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9277.0), X64 RyuJIT VectorSize=256