Whenever you want to retrieve an item from a List<T> based on a predicate, the first thing that usually comes to mind is using FirstOrDefault, well what about the Find method? Using the Find method is way more performant that you thought it was and it does the exact same thing as FirstOrDefault. Let see the benchmark and the results:
[MemoryDiagnoser]
[RankColumn]
public class FindVsFirstOrDefault
{
private List<int> _list;
private List<Car> _cars;
[Params(10)]
public int Number;
[GlobalSetup]
public void GlobalSetup()
{
_list = new List<int>(Enumerable.Range(1, Number));
SetupCars();
}
[Benchmark]
public int FindList()
{
return _list.Find(i => i > 5);
}
[Benchmark]
public int FirstOrDefaultList()
{
return _list.FirstOrDefault(i => i > 5);
}
[Benchmark]
public Car FindCars()
{
return _cars.Find(c => c.Year > 2005);
}
[Benchmark]
public Car FirstOrDefaultCars()
{
return _cars.FirstOrDefault(c => c.Year > 2005);
}
private void SetupCars()
{
_cars = new List<Car>(Number);
for (int i = 0; i < Number; i++)
{
_cars.Add(new Car
{
Name = $"Car{i}",
Year = 2000 + i,
Month = 1 + i,
Day = 1 + i
});
}
}
}
public class Car
{
public string Name { get; set; }
public int Year { get; set; }
public int Month { get; set; }
public int Day { get; set; }
}
| Method | Number | Mean | Error | StdDev | Rank | Gen0 | Allocated |
|---|---|---|---|---|---|---|---|
| FindList | 10 | 9.250 ns | 0.0194 ns | 0.0172 ns | 1 | – | – |
| FirstOrDefaultList | 10 | 52.044 ns | 0.9413 ns | 0.7860 ns | 3 | 0.0048 | 40 B |
| FindCars | 10 | 13.931 ns | 0.0463 ns | 0.0433 ns | 2 | – | – |
| FirstOrDefaultCars | 10 | 71.897 ns | 1.1182 ns | 0.9338 ns | 4 | 0.0048 | 40 B |
In .NET 9 FirstOrDefault will be faster than find so this tip applies to versions lower than .NET 8.
Leave a comment