C#idiomatic C#
linqcsharp/fundamentals/statements

Language

LINQ queries

Query collections with LINQ by using query syntax, method syntax, common operators, and lambda expressions.

  • page csharp/fundamentals/statements/linq
  • updated 07/15/2026

Language Integrated Query (LINQ) is the C# feature set for querying data with C# syntax. Many LINQ operators use deferred execution: they describe the result first and read the data later, when your code asks for the results. A query describes which data to read and how to shape the result. A query reads from a data source. A data source can be an in-memory collection, such as an array or System.Collections.Generic.List, or an external source, such as a database or XML, exposed through a LINQ provider. A LINQ provider is a library that connects LINQ syntax to a specific kind of data source. This article uses in-memory collections for its examples. A sequence is an ordered set of elements represented by System.Collections.Generic.IEnumerable. For more information about provider-based queries, see Language Integrated Query (LINQ).

LINQ query expression syntax

The examples in this article read in-memory collections such as arrays and System.Collections.Generic.List. A query usually has three parts: specify the data source, describe the result, and enumerate the source to produce the result. To enumerate a sequence means to read its elements one at a time, often with foreach.

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csQuerySyntax

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

The query expression starts with from to name the data source and range variable. The where clause keeps only matching elements, orderby sorts them, and select shapes the result.

LINQ method syntax

Query syntax uses clauses such as from, where, orderby, and select. Method syntax calls LINQ methods directly. For in-memory sequences, the standard LINQ methods are the built-in System.Linq.Enumerable methods for filtering, projection, sorting, grouping, and related operations.

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csMethodSyntax

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Method syntax is also called fluent syntax because each call returns a result that the next call can use. Many queries can use either form. Use the form that makes the query easiest to read.

Query syntax often reads well when the query has several clauses. The let clause gives a name to an intermediate value before the query filters, sorts, and selects the final result:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csQuerySyntaxClearer

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Method syntax often reads well for short operations. It's necessary for methods that don't have query-syntax keyword. For example, System.Linq.Enumerable.Count returns one value directly:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csMethodSyntaxClearer

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Lambda expressions and LINQ

A lambda expression is an anonymous function that you can pass as an argument. LINQ method syntax commonly uses lambda expressions to say what each operator should do with each element.

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csLambdaExpressions

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

In name => name.Length == 3, name is the input element and name.Length == 3 is the Boolean expression that decides whether the element belongs in the result. For more information about lambda expressions and delegate types, see Lambda expressions, delegates, and events in the fundamentals.

Query-syntax clauses use lambda expressions too. Clauses such as where, orderby, and select compile to method calls that take lambda expressions. The range variable becomes the lambda parameter, and the clause expression becomes the lambda body. Query syntax is a concise way to write those same lambdas:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csQuerySyntaxLambda

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Common LINQ methods

The most common LINQ methods cover the everyday steps of a query: filter data, shape results, sort, group, and summarize. These methods are in the System.Linq namespace and work with sequences such as System.Collections.Generic.IEnumerable.

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csCommonOperators

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

A projection creates a result value from each input element. In the previous example, the projection creates strings that combine a work item name and its priority.

Use System.Linq.Enumerable.GroupBy when the result should contain groups of elements that share a key. Each group is represented by System.Linq.IGrouping, which exposes the group key and the elements in that group.

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csGroupBy

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Grouping is useful for summaries, reports, and menus. For more information about joins, nested groupings, and provider-specific behavior, see Language Integrated Query (LINQ).

Run a query

Many LINQ operators use deferred execution. Deferred execution means operators that return a sequence, such as System.Linq.Enumerable.Where, System.Linq.Enumerable.Select, and System.Linq.Enumerable.OrderBy, don't run when you define them. They build the recipe for producing results. A foreach loop is one way to run that recipe:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csDeferredExecution

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Other operations run a query immediately. Operators that return a single value, such as System.Linq.Enumerable.Count, System.Linq.Enumerable.Sum, System.Linq.Enumerable.First, and System.Linq.Enumerable.Any, must read the elements when you call them so they can produce that value.

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csImmediateExecution

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

There's no single trigger that runs a query. Eager evaluation, also called immediate evaluation, runs the query right away and stores or returns the result. Scalar and aggregate operators such as System.Linq.Enumerable.Count, System.Linq.Enumerable.Sum, System.Linq.Enumerable.First, and System.Linq.Enumerable.Any use eager evaluation. So do System.Linq.Enumerable.ToList and System.Linq.Enumerable.ToArray when you need a snapshot of the current results. For more information about deferred execution, see Introduction to LINQ Queries in the LINQ documentation.

Compose queries

Real queries often grow from smaller decisions: start with a shared filter, add a sort for one screen, or apply an optional condition from user input. By composing queries, you can keep each step readable and reuse common parts instead of repeating one large query.

Imagine an app that shows open work items in several places. One view needs all open items, and another view needs only the highest-priority open items. To compose a query, start with a base query stored in a variable, then build a more specific query from it. Because execution is deferred, each step describes more of the result. No work happens until you enumerate the final query.

The following example stores the open work items in one query, then reuses that query to find the highest-priority open items:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csComposeQuerySyntax

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

You can also compose queries with method syntax. The next example starts with all open items, then conditionally adds another filter before it selects the titles:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csComposeMethodSyntax

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Composition can use either or both eager evaluation and deferred execution. Materialize a shared intermediate result with System.Linq.Enumerable.ToList or System.Linq.Enumerable.ToArray when you want that part to run once and stay fixed. Then build another deferred query from the cached results for the final output:

sample · csharpdocs/csharp/fundamentals/statements/snippets/linq-statements/Program.csComposeWithCaching

csharp
namespace LinqStatements;

public static class Program
{
    public static void Main()
    {
        QuerySyntaxExample();
        MethodSyntaxExample();
        QuerySyntaxClearerExample();
        MethodSyntaxClearerExample();
        LambdaExpressionsExample();
        QuerySyntaxLambdaExample();
        CommonOperatorsExample();
        GroupByExample();
        DeferredExecutionExample();
        ImmediateExecutionExample();
        ComposeQuerySyntaxExample();
        ComposeMethodSyntaxExample();
        ComposeWithCachingExample();
    }

    private static void QuerySyntaxExample()
    {
        // <QuerySyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query =
            from name in names
            where name.Length >= 4
            orderby name
            select name;

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </QuerySyntax>
    }

    private static void MethodSyntaxExample()
    {
        // <MethodSyntax>
        string[] names = ["Ana", "Ben", "Cleo", "Dara"];

        IEnumerable<string> query = names
            .Where(name => name.Length >= 4)
            .OrderBy(name => name)
            .Select(name => name);

        foreach (string name in query)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    Cleo
        //    Dara
        //
        // </MethodSyntax>
    }

    private static void QuerySyntaxClearerExample()
    {
        // <QuerySyntaxClearer>
        (string Area, int Priority)[] workItems =
        [
            ("docs", 2),
            ("tests", 1),
            ("deploy", 4),
            ("api", 1)
        ];

        IEnumerable<string> nextItems =
            from item in workItems
            let label = $"{item.Area}: P{item.Priority}"
            where item.Priority <= 2
            orderby item.Priority, item.Area
            select label;

        foreach (string item in nextItems)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    api: P1
        //    tests: P1
        //    docs: P2
        //
        // </QuerySyntaxClearer>
    }

    private static void MethodSyntaxClearerExample()
    {
        // <MethodSyntaxClearer>
        List<string> workItems = ["design", "docs", "deploy", "review"];

        int count = workItems.Count(item => item.StartsWith('d'));

        Console.WriteLine($"Starts with d: {count}"); // => Starts with d: 3
        // </MethodSyntaxClearer>
    }

    private static void LambdaExpressionsExample()
    {
        // <LambdaExpressions>
        string[] names = ["Ana", "Ben", "Cleo"];

        IEnumerable<string> shortNames = names
            .Where(name => name.Length == 3)
            .Select(name => name.ToUpperInvariant());

        foreach (string name in shortNames)
        {
            Console.WriteLine(name);
        }
        // This example produces the following output:
        //
        //    ANA
        //    BEN
        //
        // </LambdaExpressions>
    }

    private static void QuerySyntaxLambdaExample()
    {
        // <QuerySyntaxLambda>
        string[] workItems = ["docs", "test", "deploy"];

        IEnumerable<string> querySyntax =
            from item in workItems
            where item.Length == 4
            select item;

        IEnumerable<string> methodSyntax =
            workItems.Where(item => item.Length == 4);

        foreach (string item in querySyntax)
        {
            Console.WriteLine($"Result: {item}");
        }

        foreach (string item in methodSyntax)
        {
            Console.WriteLine($"Result: {item}");
        }
        // This example produces the following output:
        //
        //    Result: docs
        //    Result: test
        //    Result: docs
        //    Result: test
        //
        // </QuerySyntaxLambda>
    }

    private static void CommonOperatorsExample()
    {
        // <CommonOperators>
        Dictionary<string, int> priorities = new()
        {
            ["Docs"] = 2,
            ["Code"] = 1,
            ["Test"] = 3,
            ["Deploy"] = 4
        };

        IEnumerable<string> plannedWork = priorities
            .Where(workItem => workItem.Value <= 3)
            .OrderBy(workItem => workItem.Value)
            .Select(workItem => $"{workItem.Key}: {workItem.Value}");

        foreach (string item in plannedWork)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    Code: 1
        //    Docs: 2
        //    Test: 3
        //
        // </CommonOperators>
    }

    private static void GroupByExample()
    {
        // <GroupBy>
        string[] labels = ["api", "auth", "docs", "deploy"];

        IEnumerable<IGrouping<char, string>> groups = labels.GroupBy(label => label[0]);

        foreach (IGrouping<char, string> group in groups)
        {
            Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");
        }
        // This example produces the following output:
        //
        //    a: api, auth
        //    d: docs, deploy
        //
        // </GroupBy>
    }

    private static void DeferredExecutionExample()
    {
        // <DeferredExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        workItems.Add("deploy");

        // The query runs here, when foreach asks for the results.
        foreach (string item in query)
        {
            Console.WriteLine(item);
        }
        // This example produces the following output:
        //
        //    design
        //    docs
        //    deploy
        //
        // </DeferredExecution>
    }

    private static void ImmediateExecutionExample()
    {
        // <ImmediateExecution>
        List<string> workItems = ["design", "docs"];

        IEnumerable<string> query = workItems.Where(item => item.StartsWith('d'));

        // Count() reads the matching elements right when this line runs.
        int count = query.Count();
        Console.WriteLine($"Count before add: {count}");

        workItems.Add("deploy");

        Console.WriteLine($"Stored count: {count}");
        Console.WriteLine($"Current count: {query.Count()}");
        // This example produces the following output:
        //
        //    Count before add: 2
        //    Stored count: 2
        //    Current count: 3
        //
        // </ImmediateExecution>
    }

    private static void ComposeQuerySyntaxExample()
    {
        // <ComposeQuerySyntax>
        (string Title, int Priority, bool IsOpen)[] items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false),
            ("api", 1, true)
        ];

        IEnumerable<(string Title, int Priority, bool IsOpen)> openItems =
            from item in items
            where item.IsOpen
            select item;

        IEnumerable<string> topOpenItems =
            from item in openItems
            where item.Priority == 1
            orderby item.Title
            select item.Title;

        foreach (string title in topOpenItems)
        {
            Console.WriteLine(title);
        }
        // This example produces the following output:
        //
        //    api
        //    tests
        //
        // </ComposeQuerySyntax>
    }

    private static void ComposeMethodSyntaxExample()
    {
        // <ComposeMethodSyntax>
        (string Title, string Area, bool IsOpen)[] items =
        [
            ("write docs", "docs", true),
            ("fix tests", "tests", true),
            ("deploy site", "deploy", false)
        ];

        bool onlyDocs = true;

        IEnumerable<(string Title, string Area, bool IsOpen)> query =
            items.Where(item => item.IsOpen);

        if (onlyDocs)
        {
            query = query.Where(item => item.Area == "docs");
        }

        foreach (string title in query.Select(item => item.Title))
        {
            Console.WriteLine(title); // => write docs
        }
        // </ComposeMethodSyntax>
    }

    private static void ComposeWithCachingExample()
    {
        // <ComposeWithCaching>
        List<(string Title, int Priority, bool IsOpen)> items =
        [
            ("docs", 2, true),
            ("tests", 1, true),
            ("deploy", 3, false)
        ];

        List<(string Title, int Priority, bool IsOpen)> openItems = items
            .Where(item => item.IsOpen)
            .ToList();

        items.Add(("api", 1, true));

        IEnumerable<string> cachedTopOpenItems = openItems
            .Where(item => item.Priority == 1)
            .OrderBy(item => item.Title)
            .Select(item => item.Title);

        foreach (string title in cachedTopOpenItems)
        {
            Console.WriteLine(title); // => tests
        }
        // </ComposeWithCaching>
    }
}

Explore LINQ in depth

This article uses in-memory collections to teach LINQ syntax and core operators. For more information about LINQ operators and advanced scenarios, see Language Integrated Query (LINQ). That article covers joins, XML, database providers, dynamic queries, and custom operators.

See also