Почему LINQ .Where(predicate).First() быстрее, чем .First(predicate)?

Я провожу некоторые тесты производительности и заметил, что выражение LINQ типа

result = list.First(f => f.Id == i).Property

работает медленнее, чем

result = list.Where(f => f.Id == i).First().Property

Это кажется контр-интуитивным. Я бы подумал, что первое выражение будет быстрее, потому что оно может прекратить итерацию по списку, как только предикат будет удовлетворен, тогда как я бы подумал, что выражение .Where() может итерировать весь список перед вызовом .First() на полученном подмножестве. Даже если последнее и замыкается, это не должно быть быстрее, чем прямое использование First, но это так.

Ниже приведены два действительно простых модульных теста, которые иллюстрируют это. При компиляции с оптимизацией TestWhereAndFirst примерно на 30% быстрее, чем TestFirstOnly на .Net и Silverlight 4. Я пробовал заставить предикат возвращать больше результатов, но разница в производительности осталась прежней.

Может ли кто-нибудь объяснить, почему .First(fn) медленнее, чем .Where(fn).First()? Я вижу аналогичный контр-интуитивный результат с .Count(fn) по сравнению с .Where(fn).Count().

private const int Range = 50000;

private class Simple
{
   public int Id { get; set; }
   public int Value { get; set; }
}

[TestMethod()]
public void TestFirstOnly()
{
   List<Simple> list = new List<Simple>(Range);
   for (int i = Range - 1; i >= 0; --i)
   {
      list.Add(new Simple { Id = i, Value = 10 });
   }

   int result = 0;
   for (int i = 0; i < Range; ++i)
   {
      result += list.First(f => f.Id == i).Value;
   }

   Assert.IsTrue(result > 0);
}

[TestMethod()]
public void TestWhereAndFirst()
{
   List<Simple> list = new List<Simple>(Range);
   for (int i = Range - 1; i >= 0; --i)
   {
      list.Add(new Simple { Id = i, Value = 10 });
   }

   int result = 0;
   for (int i = 0; i < Range; ++i)
   {
      result += list.Where(f => f.Id == i).First().Value;
   }

   Assert.IsTrue(result > 0);
}
69
задан dazza 29 December 2011 в 20:51
поделиться