Одна вещь, которую мы определили как проблему производительности, - это создание большого количества лямбд и перебор небольших коллекций. Что происходит в преобразованном образце?
Ninjas.FirstOrDefault(ninja => ninja.Id == ninjaId)
Сначала создается новый экземпляр (сгенерированного) типа замыкания. Новый экземпляр в управляемой куче, некоторая работа для GC.
Во-вторых, новый экземпляр делегата создается из метода в этом замыкании.
Затем вызывается метод FirstOrDefault. Что оно делает?
Он повторяет коллекцию (так же, как ваш исходный код) и вызывает делегат.
Итак, у вас есть 4 вещи, добавленные здесь:
1. Создать закрытие
2. Создать делегата
3. Позвоните через делегата
4. Соберите закрытие и делегируйте
Если вы звоните FindNinjaById много раз, вы добавите это, чтобы стать важным ударом по производительности. Конечно, измерить.
Если вы замените его на (эквивалент)
Ninjas.Where(ninja => ninja.Id == ninjaId).FirstOrDefault()
добавляет
5. Создание конечного автомата для итератора («Где» - это функция выдачи)