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; }
}
MethodNumberMeanErrorStdDevRankGen0Allocated
FindList109.250 ns0.0194 ns0.0172 ns1
FirstOrDefaultList1052.044 ns0.9413 ns0.7860 ns30.004840 B
FindCars1013.931 ns0.0463 ns0.0433 ns2
FirstOrDefaultCars1071.897 ns1.1182 ns0.9338 ns40.004840 B
benchmark .NET results in .NET 7

In .NET 9 FirstOrDefault will be faster than find so this tip applies to versions lower than .NET 8.

Leave a comment

Trending