org.sonar.plugins.csharp.S6605.html Maven / Gradle / Ivy
Why is this an issue?
Both the List.Exists
method and IEnumerable.Any
method can be used to find the first element that satisfies a predicate
in a collection. However, List.Exists
can be faster than IEnumerable.Any
for List
objects, as well as requires
significantly less memory. For small collections, the performance difference may be negligible, but for large collections, it can be noticeable. The
same applies to ImmutableList
and arrays too.
Applies to
What is the potential impact?
We measured at least 3x improvement in execution time. For more details see the Benchmarks
section from the More info
tab.
Also, no memory allocations were needed for the Exists
method, since the search is done in-place.
Exceptions
Since LINQ to
Entities
relies a lot on System.Linq
for query conversion,
this rule won’t raise when used within LINQ to Entities syntaxes.
How to fix it
The Exists
method is defined on the collection class, and it has the same signature as Any
extension method if a
predicate is used. The method can be replaced in place.
Code examples
Noncompliant code example
bool ContainsEven(List<int> data) =>
data.Any(x => x % 2 == 0);
bool ContainsEven(int[] data) =>
data.Any(x => x % 2 == 0);
Compliant solution
bool ContainsEven(List<int> data) =>
data.Exists(x => x % 2 == 0);
bool ContainsEven(int[] data) =>
Array.Exists(data, x => x % 2 == 0);
Resources
Documentation
- List<T>.Exists(Predicate<T>)
- Array.Exists<T>(T[], Predicate<T>)
- ImmutableList<T>.Exists(Predicate<T>)
- Enumerable.Any(Predicate<T>)
- LINQ to Entities
Benchmarks
Method
Runtime
Mean
Standard Deviation
Allocated
Any
.NET 7.0
6.670 ms
0.1413 ms
40004 B
Exists
.NET 7.0
1.364 ms
0.0270 ms
1 B
Any
.NET Framework 4.6.2
5.380 ms
0.0327 ms
40128 B
Exists
.NET Framework 4.6.2
1.575 ms
0.0348 ms
-
Glossary
The results were generated by running the following snippet with BenchmarkDotNet:
private List<int> data;
private readonly Random random = new Random();
[Params(1_000)]
public int N { get; set; }
[GlobalSetup]
public void Setup() =>
data = Enumerable.Range(0, N).Select(x => 43).ToList();
[Benchmark(Baseline = true)]
public void Any()
{
for (var i = 0; i < N; i++)
{
_ = data.Any(x => x % 2 == 0); // Enumerable.Any
}
}
[Benchmark]
public void Exists()
{
for (var i = 0; i < N; i++)
{
_ = data.Exists(x => x % 2 == 0); // List<T>.Exists
}
}
Hardware configuration:
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2846/22H2/2022Update)
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 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.1 (4.8.9139.0), X64 RyuJIT VectorSize=256