org.sonar.plugins.csharp.S6608.html Maven / Gradle / Ivy
Why is this an issue?
Indexes in C# provide direct access to an element at a specific position within an array or collection. When compared to Enumerable
methods, indexing can be more efficient for certain scenarios, such as iterating over a large collection, due to avoiding the overhead of checking the
underlying collection type before accessing it.
This applies to types that implement one of these interfaces:
What is the potential impact?
We measured a significant improvement in execution time. For more details see the Benchmarks
section from the More info
tab.
How to fix it
If the type you are using implements IList
, IList<T>
or IReadonlyList<T>
, it implements
this[int index]
. This means calls to First
, Last
, or ElementAt(index)
can be replaced with
indexing at 0
, Count-1
and index
respectively.
Code examples
Noncompliant code example
int GetAt(List<int> data, int index)
=> data.ElementAt(index);
int GetFirst(List<int> data)
=> data.First();
int GetLast(List<int> data)
=> data.Last();
Compliant solution
int GetAt(List<int> data, int index)
=> data[index];
int GetFirst(List<int> data)
=> data[0];
int GetLast(List<int> data)
=> data[data.Count-1];
Resources
Documentation
Benchmarks
Method
Runtime
Mean
Standard Deviation
ElementAt
3,403.4 ns
28.52 ns
26.67 ns
Index
478.0 ns
6.93 ns
6.48 ns
First
6,160.0 ns
57.66 ns
53.93 ns
First_Index
485.7 ns
5.81 ns
5.15 ns
Last
6,034.3 ns
20.34 ns
16.98 ns
Last_Index
408.3 ns
2.54 ns
2.38 ns
Glossary
The results were generated by running the following snippet with BenchmarkDotNet:
private List<byte> data;
private Random random;
[Params(1_000_000)]
public int SampleSize;
[Params(1_000)]
public int LoopSize;
[GlobalSetup]
public void Setup()
{
random = new Random(42);
var bytes = new byte[SampleSize];
random.NextBytes(bytes);
data = bytes.ToList();
}
[Benchmark]
public int ElementAt()
{
int result = default;
for (var i = 0; i < LoopSize; i++)
{
result = data.ElementAt(i);
}
return result;
}
[Benchmark]
public int Index()
{
int result = default;
for (var i = 0; i < LoopSize; i++)
{
result = data[i];
}
return result;
}
[Benchmark]
public int First()
{
int result = default;
for (var i = 0; i < LoopSize; i++)
{
result = data.First();
}
return result;
}
[Benchmark]
public int First_Index()
{
int result = default;
for (var i = 0; i < LoopSize; i++)
{
result = data[0];
}
return result;
}
[Benchmark]
public int Last()
{
int result = default;
for (var i = 0; i < LoopSize; i++)
{
result = data.Last();
}
return result;
}
[Benchmark]
public int Last_Index()
{
int result = default;
for (var i = 0; i < LoopSize; i++)
{
result = data[data.Count - 1];
}
return result;
}
Hardware configuration:
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.4412/22H2/2022Update)
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=8.0.301
[Host] : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX2
.NET 8.0 : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX2