org.sonar.plugins.csharp.S6602.html Maven / Gradle / Ivy
Why is this an issue?
Both the List.Find
method and IEnumerable.FirstOrDefault
method can be used to find the first element that satisfies a
given condition in a collection. However, List.Find
can be faster than IEnumerable.FirstOrDefault
for List
objects. For small collections, the performance difference may be minor, but for large collections, it can make a noticeable difference. The same
applies for ImmutableList
and arrays too.
Applies to
What is the potential impact?
We measured at least 2x improvement in the execution time. For more details see the Benchmarks
section from the More info
tab.
How to fix it
The Find
method is defined on the collection class, and it has the same signature as FirstOrDefault
extension method. The
function can be replaced in place.
Code examples
Noncompliant code example
int GetValue(List<int> data) =>
data.FirstOrDefault(x => x % 2 == 0);
int GetValue(int[] data) =>
data.FirstOrDefault(x => x % 2 == 0);
Compliant solution
int GetValue(List<int> data) =>
data.Find(x => x % 2 == 0);
int GetValue(int[] data) =>
Array.Find(data, x => x % 2 == 0);
Resources
Documentation
- List<T>.Find(Predicate<T>)
- Array.Find<T>(T[], Predicate<T>)
- ImmutableList<T>.Find(Predicate<T>)
- Enumerable.FirstOrDefault(Predicate<T>)
Benchmarks
Method
Runtime
Mean
Standard Deviation
Allocated
FirstOrDefault
.NET 7.0
5.373 ms
0.1049 ms
125 KB
Find
.NET 7.0
1.691 ms
0.0334 ms
85.94 KB
FirstOrDefault
.NET Framework 4.6.2
5.035 ms
0.0421 ms
125.38 KB
Find
.NET Framework 4.6.2
1.779 ms
0.0107 ms
86.2 KB
Glossary
The results were generated by running the following snippet with BenchmarkDotNet:
private List<string> data;
private Random random = new Random();
[Params(1_000)]
public int N { get; set; }
[GlobalSetup]
public void Setup() =>
data = Enumerable.Range(0, N).Select(x => Guid.NewGuid().ToString()).ToList();
[Benchmark(Baseline = true)]
public void FirstOrDefault()
{
for (var i = 0; i < N; i++)
{
var value = data[random.Next(N - 1)];
_ = data.FirstOrDefault(x => x == value); // Enumerable.FirstOrDefault()
}
}
[Benchmark]
public void Find()
{
for (var i = 0; i < N; i++)
{
var value = data[random.Next(N - 1)];
_ = data.Find(x => x == value); // List<T>.Find()
}
}
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
[Host] : .NET Framework 4.8 (4.8.4614.0), X64 RyuJIT VectorSize=256
.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