Table of Contents

Sample: IntroDeferredExecution

In LINQ, execution of a query is usually deferred until the moment when you actually request the data. If your benchmark just returns IEnumerable or IQueryable it's not measuring the execution of the query, just the creation.

This is why we decided to warn you about this issue whenever it happens:

Benchmark IntroDeferredExecution.Wrong returns a deferred execution result (IEnumerable<Int32>). You need to either change the method declaration to return a materialized result or consume it on your own. You can use .Consume() extension method to do that.

Don't worry! We are also providing you with a Consume extension method which can execute given IEnumerable or IQueryable and consume its results. All you need to do is to create a Consumer instance, preferably store it in a field (to exclude the cost of creating Consumer from the benchmark itself) and pass it to Consume extension method.

Do not call .ToArray() because it's an expensive operation and it might dominate given benchmark!

Source code

using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;

namespace BenchmarkDotNet.Samples
{
    public class IntroDeferredExecution
    {
        private readonly int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        private readonly Consumer consumer = new Consumer();

        /// <summary>
        /// this benchmark returns a deferred LINQ query which is NOT executed
        /// so the benchmark measures the cost of creating the query, not the actual execution
        /// this is WRONG
        /// You can read more about LINQ and Deferred Execution <see href="https://blogs.msdn.microsoft.com/charlie/2007/12/10/linq-and-deferred-execution/">here</see>
        /// </summary>
        /// <returns>deferred LINQ query</returns>
        [Benchmark]
        public IEnumerable<int> Wrong() => from number in numbers orderby number descending select number;

        /// <summary>
        /// this benchmark uses .Consume extension method which executes given deferred query and consumes its result
        /// so the benchmark measures the cost of creating the query and executing it
        /// </summary>
        [Benchmark]
        public void Ok() => (from number in numbers orderby number descending select number).Consume(consumer);
    }
}