From e0775e0e933c71dfdba5d3d39184b21e6c9a38b8 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 1 Dec 2025 15:58:55 -0500 Subject: [PATCH 1/3] Update for the new extensions Fixes #45758 Update the LINQ section to highlight C# 14 extension members over the C# 3 style `this` extension methods. In general, refer to "extension members" over "extension methods" when discussing the language feature. Use "extension methods" in the context of writing *methods* specifically, as in the query expression pattern. --- .../get-started/features-that-support-linq.md | 44 +++++++-------- .../linq/get-started/write-linq-queries.md | 53 ++++++++++--------- docs/csharp/linq/how-to-extend-linq.md | 33 ++++++------ docs/csharp/linq/index.md | 26 ++++----- .../linq/standard-query-operators/index.md | 31 +++++------ 5 files changed, 96 insertions(+), 91 deletions(-) diff --git a/docs/csharp/linq/get-started/features-that-support-linq.md b/docs/csharp/linq/get-started/features-that-support-linq.md index 8761fcc66e4e8..04e6b6827da64 100644 --- a/docs/csharp/linq/get-started/features-that-support-linq.md +++ b/docs/csharp/linq/get-started/features-that-support-linq.md @@ -1,15 +1,16 @@ --- -title: "Language Features That Support LINQ" +title: "Language features that support LINQ" description: Learn about C# features to use with LINQ queries and in other contexts. -ms.date: 04/22/2024 +ms.date: 12/01/2025 +ai-usage: ai-assisted helpviewer_keywords: - "LINQ [C#], features supporting LINQ" --- -# C# Features That Support LINQ +# C# features that support LINQ -## Query Expressions +## Query expressions -Query expressions use a declarative syntax similar to SQL or XQuery to query over collections. At compile time, query syntax is converted to method calls to a LINQ provider's implementation of the standard query methods. Applications control the standard query operators that are in scope by specifying the appropriate namespace with a [`using`](../../language-reference/keywords/using-directive.md) directive. The following query expression takes an array of strings, groups them according to the first character in the string, and orders the groups. +Query expressions use a declarative syntax similar to SQL or XQuery to query over collections. At compile time, the compiler converts query syntax to method calls to a LINQ provider's implementation of the standard query methods. Applications control the standard query operators that are in scope by specifying the appropriate namespace with a [`using`](../../language-reference/keywords/using-directive.md) directive. The following query expression takes an array of strings, groups them according to the first character in the string, and orders the groups. ```csharp var query = from str in stringArray @@ -18,7 +19,7 @@ var query = from str in stringArray select stringGroup; ``` -## Implicitly Typed Variables (var) +## Implicitly typed variables (var) You can use the [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) modifier to instruct the compiler to infer and assign the type, as shown here: @@ -30,17 +31,17 @@ var query = from str in stringArray select str; ``` -Variables declared as `var` are strongly typed, just like variables whose type you specify explicitly. The use of `var` makes it possible to create anonymous types, but only for local variables. For more information, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md). +Variables declared as `var` are strongly typed, just like variables whose type you specify explicitly. Using `var` makes it possible to create anonymous types, but only for local variables. For more information, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md). -## Object and Collection Initializers +## Object and collection initializers -Object and collection initializers make it possible to initialize objects without explicitly calling a constructor for the object. Initializers are typically used in query expressions when they project the source data into a new data type. Assuming a class named `Customer` with public `Name` and `Phone` properties, the object initializer can be used as in the following code: +Object and collection initializers make it possible to initialize objects without explicitly calling a constructor for the object. You typically use initializers in query expressions when they project the source data into a new data type. Assuming a class named `Customer` with public `Name` and `Phone` properties, you can use the object initializer as in the following code: ```csharp var cust = new Customer { Name = "Mike", Phone = "555-1212" }; ``` -Continuing with your `Customer` class, assume that there's a data source called `IncomingOrders`, and that for each order with a large `OrderSize`, you would like to create a new `Customer` based off of that order. A LINQ query can be executed on this data source and use object initialization to fill a collection: +Continuing with your `Customer` class, assume that there's a data source called `IncomingOrders`, and that for each order with a large `OrderSize`, you want to create a new `Customer` based off of that order. You can execute a LINQ query on this data source and use object initialization to fill a collection: ```csharp var newLargeOrderCustomers = from o in IncomingOrders @@ -48,7 +49,7 @@ var newLargeOrderCustomers = from o in IncomingOrders select new Customer { Name = o.Name, Phone = o.Phone }; ``` -The data source might have more properties defined than the `Customer` class such as `OrderSize`, but with object initialization, the data returned from the query is molded into the desired data type; you choose the data that is relevant to your class. As a result, you now have an filled with the new `Customer`s you wanted. The preceding example can also be written in LINQ's method syntax: +The data source might have more properties defined than the `Customer` class such as `OrderSize`, but with object initialization, the data returned from the query is molded into the desired data type; you choose the data that's relevant to your class. As a result, you now have an filled with the new `Customer`s you wanted. You can also write the preceding example in LINQ's method syntax: ```csharp var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name = y.Name, Phone = y.Phone }); @@ -61,9 +62,9 @@ For more information, see: - [Object and Collection Initializers](../../programming-guide/classes-and-structs/object-and-collection-initializers.md) - [Query Expression Syntax for Standard Query Operators](../standard-query-operators/index.md) -## Anonymous Types +## Anonymous types -The compiler constructs an [anonymous type](../../fundamentals/types/anonymous-types.md). The type name is only available to the compiler. Anonymous types provide a convenient way to group a set of properties temporarily in a query result without having to define a separate named type. Anonymous types are initialized with a new expression and an object initializer, as shown here: +The compiler constructs an [anonymous type](../../fundamentals/types/anonymous-types.md). Only the compiler can access the type name. Anonymous types provide a convenient way to group a set of properties temporarily in a query result without having to define a separate named type. You initialize anonymous types with a new expression and an object initializer, as shown here: ```csharp select new {name = cust.Name, phone = cust.Phone}; @@ -71,35 +72,36 @@ select new {name = cust.Name, phone = cust.Phone}; Beginning with C# 7, you can use [tuples](../../language-reference/builtin-types/value-tuples.md) to create unnamed types. -## Extension Methods +## Extension members -An [extension method](../../programming-guide/classes-and-structs/extension-methods.md) is a static method that can be associated with a type, so that it can be called as if it were an instance method on the type. This feature enables you to, in effect, "add" new methods to existing types without actually modifying them. The standard query operators are a set of extension methods that provide LINQ query functionality for any type that implements . +An [extension member](../../programming-guide/classes-and-structs/extension-methods.md) is a static member of a static class associated with a type called the *receiver type*. You can call an extension member as if it were a member of the receiver type. This feature enables you to "add" new members to existing types without actually modifying them. The standard query operators are a set of extension methods that provide LINQ query functionality for any type that implements . -## Lambda Expressions +## Lambda expressions -A [lambda expressions](../../language-reference/operators/lambda-expressions.md) is an inline function that uses the `=>` operator to separate input parameters from the function body and can be converted at compile time to a delegate or an expression tree. In LINQ programming, you encounter lambda expressions when you make direct method calls to the standard query operators. +A [lambda expression](../../language-reference/operators/lambda-expressions.md) is an inline function that uses the `=>` operator to separate input parameters from the function body and can be converted at compile time to a delegate or an expression tree. In LINQ programming, you encounter lambda expressions when you make direct method calls to the standard query operators. ## Expressions as data -Query objects are composable, meaning that you can return a query from a method. Objects that represent queries don't store the resulting collection, but rather the steps to produce the results when needed. The advantage of returning query objects from methods is that they can be further composed or modified. Therefore any return value or `out` parameter of a method that returns a query must also have that type. If a method materializes a query into a concrete or type, it returns the query results instead of the query itself. A query variable that is returned from a method can still be composed or modified. +Query objects are composable, meaning that you can return a query from a method. Objects that represent queries don't store the resulting collection, but rather the steps to produce the results when needed. The advantage of returning query objects from methods is that you can further compose or modify them. Therefore, any return value or `out` parameter of a method that returns a query must also have that type. If a method materializes a query into a concrete or type, it returns the query results instead of the query itself. You can still compose or modify a query variable that's returned from a method. -In the following example, the first method `QueryMethod1` returns a query as a return value, and the second method `QueryMethod2` returns a query as an `out` parameter (`returnQ` in the example). In both cases, it's a query that is returned, not query results. +In the following example, the first method `QueryMethod1` returns a query as a return value, and the second method `QueryMethod2` returns a query as an `out` parameter (`returnQ` in the example). In both cases, it's a query that's returned, not query results. :::code language="csharp" source="./snippets/SnippetApp/ReturnQueryFromMethod.cs" id="return_query_from_method_1"::: -Query `myQuery1` is executed in the following foreach loop. +The following `foreach` loop executes query `myQuery1`. :::code language="csharp" source="./snippets/SnippetApp/ReturnQueryFromMethod.cs" id="return_query_from_method_2"::: Rest the mouse pointer over `myQuery1` to see its type. -You also can execute the query returned from `QueryMethod1` directly, without using `myQuery1`. +You can also execute the query returned from `QueryMethod1` directly, without using `myQuery1`. :::code language="csharp" source="./snippets/SnippetApp/ReturnQueryFromMethod.cs" id="return_query_from_method_3"::: Rest the mouse pointer over the call to `QueryMethod1` to see its return type. `QueryMethod2` returns a query as the value of its `out` parameter: + :::code language="csharp" source="./snippets/SnippetApp/ReturnQueryFromMethod.cs" id="return_query_from_method_4"::: You can modify a query by using query composition. In this case, the previous query object is used to create a new query object. This new object returns different results than the original query object. diff --git a/docs/csharp/linq/get-started/write-linq-queries.md b/docs/csharp/linq/get-started/write-linq-queries.md index 6e64fab2fd58d..32031310d5105 100644 --- a/docs/csharp/linq/get-started/write-linq-queries.md +++ b/docs/csharp/linq/get-started/write-linq-queries.md @@ -1,13 +1,14 @@ --- title: Write LINQ queries description: Learn how to write LINQ queries in C#. -ms.date: 01/16/2025 +ms.date: 12/01/2025 +ai-usage: ai-assisted --- # Write C# LINQ queries to query data -Most queries in the introductory Language Integrated Query (LINQ) documentation are written by using the LINQ declarative query syntax. The C# compiler translates query syntax into method calls. These method calls implement the standard query operators, and have names such as `Where`, `Select`, `GroupBy`, `Join`, `Max`, and `Average`. You can call them directly by using method syntax instead of query syntax. +Most queries in the introductory Language Integrated Query (LINQ) documentation use the LINQ declarative query syntax. The C# compiler translates query syntax into method calls. These method calls implement the standard query operators and have names such as `Where`, `Select`, `GroupBy`, `Join`, `Max`, and `Average`. You can call them directly by using method syntax instead of query syntax. -Query syntax and method syntax are semantically identical, but query syntax is often simpler and easier to read. Some queries must be expressed as method calls. For example, you must use a method call to express a query that retrieves the number of elements that match a specified condition. You also must use a method call for a query that retrieves the element that has the maximum value in a source sequence. The reference documentation for the standard query operators in the namespace generally uses method syntax. You should become familiar with how to use method syntax in queries and in query expressions themselves. +Query syntax and method syntax are semantically identical, but query syntax is often simpler and easier to read. You must express some queries as method calls. For example, you must use a method call to express a query that retrieves the number of elements that match a specified condition. You also must use a method call for a query that retrieves the element that has the maximum value in a source sequence. The reference documentation for the standard query operators in the namespace generally uses method syntax. Become familiar with how to use method syntax in queries and in query expressions themselves. ## Standard query operator extension methods @@ -21,13 +22,13 @@ On the right side of the expression, notice that the `where` clause is now expre ![Screenshot showing all the standard query operators in Intellisense.](./media/write-linq-queries/standard-query-operators.png) -Although it looks as if includes more methods, it doesn't. The standard query operators are implemented as *extension methods*. Extensions methods "extend" an existing type; they can be called as if they were instance methods on the type. The standard query operators extend and that is why you can write `numbers.Where(...)`. You bring extensions into scope with `using` directives before calling them. +Although it looks as if includes more methods, it doesn't. The standard query operators are implemented as *extension methods*. Extension members "extend" an existing type; they can be called as if they were members on the type. The standard query operators extend , and that's why you can write `numbers.Where(...)`. You bring extensions into scope with `using` directives before calling them. -For more information about extension methods, see [Extension Methods](../../programming-guide/classes-and-structs/extension-methods.md). For more information about standard query operators, see [Standard Query Operators Overview (C#)](../standard-query-operators/index.md). Some LINQ providers, such as [Entity Framework](/ef/core/) and LINQ to XML, implement their own standard query operators and extension methods for other types besides . +For more information about extension members, see [Extension members](../../programming-guide/classes-and-structs/extension-methods.md). For more information about standard query operators, see [Standard Query Operators Overview (C#)](../standard-query-operators/index.md). Some LINQ providers, such as [Entity Framework](/ef/core/) and LINQ to XML, implement their own standard query operators and extension members for other types besides . ## Lambda expressions -In the preceding example, the conditional expression (`num % 2 == 0`) is passed as an in-line argument to the method: `Where(num => num % 2 == 0).` This inline expression is a [lambda expression](../../language-reference/operators/lambda-expressions.md). It's a convenient way to write code that would otherwise have to be written in more cumbersome form. The `num` on the left of the operator is the input variable, which corresponds to `num` in the query expression. The compiler can infer the type of `num` because it knows that `numbers` is a generic type. The body of the lambda is the same as the expression in query syntax or in any other C# expression or statement. It can include method calls and other complex logic. The return value is the expression result. Certain queries can only be expressed in method syntax and some of those queries require lambda expressions. Lambda expressions are a powerful and flexible tool in your LINQ toolbox. +In the preceding example, the conditional expression (`num % 2 == 0`) is passed as an in-line argument to the method: `Where(num => num % 2 == 0).` This inline expression is a [lambda expression](../../language-reference/operators/lambda-expressions.md). It's a convenient way to write code that would otherwise have to be written in more cumbersome form. The `num` on the left of the operator is the input variable, which corresponds to `num` in the query expression. The compiler can infer the type of `num` because it knows that `numbers` is a generic type. The body of the lambda is the same as the expression in query syntax or in any other C# expression or statement. It can include method calls and other complex logic. The return value is the expression result. You can only express certain queries in method syntax, and some of those queries require lambda expressions. Lambda expressions are a powerful and flexible tool in your LINQ toolbox. ## Composability of queries @@ -36,55 +37,55 @@ In the preceding code example, the [!NOTE] -> These queries operate on in-memory collections; however, the syntax is identical to that used in LINQ to Entities and LINQ to XML. +> These queries operate on in-memory collections; however, the syntax is identical to the syntax used in LINQ to Entities and LINQ to XML. -## Example - Query syntax +## Example - query syntax -You write most queries with *query syntax* to create *query expressions*. The following example shows three query expressions. The first query expression demonstrates how to filter or restrict results by applying conditions with a `where` clause. It returns all elements in the source sequence whose values are greater than 7 or less than 3. The second expression demonstrates how to order the returned results. The third expression demonstrates how to group results according to a key. This query returns two groups based on the first letter of the word. +Write most queries with *query syntax* to create *query expressions*. The following example shows three query expressions. The first query expression demonstrates how to filter or restrict results by applying conditions with a `where` clause. It returns all elements in the source sequence whose values are greater than 7 or less than 3. The second expression demonstrates how to order the returned results. The third expression demonstrates how to group results according to a key. This query returns two groups based on the first letter of the word. :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_1"::: -The type of the queries is . All of these queries could be written using [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) as shown in the following example: +The type of the queries is . You can write all of these queries using [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) as shown in the following example: `var query = from num in numbers...` In each previous example, the queries don't actually execute until you iterate over the query variable in a [`foreach`](../../language-reference/statements/iteration-statements.md#the-foreach-statement) statement or other statement. -## Example - Method syntax +## Example - method syntax -Some query operations must be expressed as a method call. The most common such methods are those methods that return singleton numeric values, such as , , , , and so on. These methods must always be called last in any query because they return a single value and can't serve as the source for an additional query operation. The following example shows a method call in a query expression: +You must express some query operations as a method call. The most common such methods are those methods that return singleton numeric values, such as , , , , and so on. Call these methods last in any query because they return a single value and can't serve as the source for more query operations. The following example shows a method call in a query expression: :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_2"::: -If the method has or parameters, these arguments are provided in the form of a [lambda expression](../../language-reference/operators/lambda-expressions.md), as shown in the following example: +If the method has or parameters, provide these arguments in the form of a [lambda expression](../../language-reference/operators/lambda-expressions.md), as shown in the following example: :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_3"::: -In the previous queries, only Query #4 executes immediately, because it returns a single value, and not a generic collection. The method itself uses `foreach` or similar code in order to compute its value. +In the previous queries, only Query #4 executes immediately because it returns a single value, and not a generic collection. The method itself uses `foreach` or similar code in order to compute its value. -Each of the previous queries can be written by using implicit typing with [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables), as shown in the following example: +You can write each of the previous queries by using implicit typing with [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables), as shown in the following example: :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_4"::: -## Example - Mixed query and method syntax +## Example - mixed query and method syntax -This example shows how to use method syntax on the results of a query clause. Just enclose the query expression in parentheses, and then apply the dot operator and call the method. In the following example, query #7 returns a count of the numbers whose value is between 3 and 7. +This example shows how to use method syntax on the results of a query clause. Enclose the query expression in parentheses, and then apply the dot operator and call the method. In the following example, query #7 returns a count of the numbers whose value is between 3 and 7. :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_5"::: Because Query #7 returns a single value and not a collection, the query executes immediately. -The previous query can be written by using implicit typing with `var`, as follows: +You can write the previous query by using implicit typing with `var`, as follows: ```csharp var numCount = (from num in numbers... ``` -It can be written in method syntax as follows: +You can write it in method syntax as follows: :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_5a"::: -It can be written by using explicit typing, as follows: +You can write it by using explicit typing, as follows: :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_5b"::: @@ -135,23 +136,23 @@ In each of the examples, the `equals` query keyword is used. You can also use [p ## Handle exceptions in query expressions -It's possible to call any method in the context of a query expression. Don't call any method in a query expression that can create a side effect such as modifying the contents of the data source or throwing an exception. This example shows how to avoid raising exceptions when you call methods in a query expression without violating the general .NET guidelines on exception handling. Those guidelines state that it's acceptable to catch a specific exception when you understand why it was thrown in a given context. For more information, see [Best Practices for Exceptions](../../../standard/exceptions/best-practices-for-exceptions.md). +You can call any method in the context of a query expression. Don't call any method in a query expression that can create a side effect such as modifying the contents of the data source or throwing an exception. This example shows how to avoid raising exceptions when you call methods in a query expression without violating the general .NET guidelines on exception handling. Those guidelines state that it's acceptable to catch a specific exception when you understand why it's thrown in a given context. For more information, see [Best Practices for Exceptions](../../../standard/exceptions/best-practices-for-exceptions.md). The final example shows how to handle those cases when you must throw an exception during execution of a query. -The following example shows how to move exception handling code outside a query expression. This refactoring is only possible when the method doesn't depend on any variables local to the query. It's easier to deal with exceptions outside of the query expression. +The following example shows how to move exception handling code outside a query expression. You can only refactor this way when the method doesn't depend on any variables local to the query. It's easier to deal with exceptions outside of the query expression. :::code language="csharp" source="./snippets/SnippetApp/Exceptions.cs" id="exceptions_1"::: -In the `catch (InvalidOperationException)` block in the preceding example, handle (or don't handle) the exception in the way that is appropriate for your application. +In the `catch (InvalidOperationException)` block in the preceding example, handle (or don't handle) the exception in the way that's appropriate for your application. -In some cases, the best response to an exception that is thrown from within a query might be to stop the query execution immediately. The following example shows how to handle exceptions that might be thrown from inside a query body. Assume that `SomeMethodThatMightThrow` can potentially cause an exception that requires the query execution to stop. +In some cases, the best response to an exception that's thrown from within a query might be to stop the query execution immediately. The following example shows how to handle exceptions that might be thrown from inside a query body. Assume that `SomeMethodThatMightThrow` can potentially cause an exception that requires the query execution to stop. -The `try` block encloses the `foreach` loop, and not the query itself. The `foreach` loop is the point at which the query is executed. Run-time exceptions are thrown when the query is executed. Therefore they must be handled in the `foreach` loop. +The `try` block encloses the `foreach` loop, and not the query itself. The `foreach` loop is the point at which the query is executed. Run-time exceptions are thrown when the query is executed. Therefore, handle them in the `foreach` loop. :::code language="csharp" source="./snippets/SnippetApp/Exceptions.cs" id="exceptions_2"::: -Remember to catch whatever exception you expect to raise and/or do any necessary cleanup in a `finally` block. +Catch whatever exception you expect to raise, and do any necessary cleanup in a `finally` block. ## See also diff --git a/docs/csharp/linq/how-to-extend-linq.md b/docs/csharp/linq/how-to-extend-linq.md index a2334c30434da..75c64c1a2f3be 100644 --- a/docs/csharp/linq/how-to-extend-linq.md +++ b/docs/csharp/linq/how-to-extend-linq.md @@ -1,22 +1,23 @@ --- -title: "How to: Write your own extensions to LINQ" +title: "Write your own extensions to LINQ" description: Learn techniques to extend the standard LINQ methods. Query based on runtime state, modify query objects, and extend LINQ capabilities. ms.topic: how-to -ms.date: 04/17/2025 +ms.date: 12/01/2025 +ai-usage: ai-assisted --- -# How to extend LINQ +# Write your own extensions to LINQ -All LINQ based methods follow one of two similar patterns. They take an enumerable sequence. They return either a different sequence, or a single value. The consistency of the shape enables you to extend LINQ by writing methods with a similar shape. In fact, the .NET libraries gained new methods in many .NET releases since LINQ was first introduced. In this article, you see examples of extending LINQ by writing your own methods that follow the same pattern. +All LINQ based methods follow one of two similar patterns. They take an enumerable sequence. They return either a different sequence or a single value. The consistency of the shape enables you to extend LINQ by writing methods with a similar shape. In fact, the .NET libraries gained new methods in many .NET releases since LINQ was first introduced. In this article, you see examples of extending LINQ by writing your own methods that follow the same pattern. ## Add custom methods for LINQ queries -You extend the set of methods that you use for LINQ queries by adding extension methods to the interface. For example, in addition to the standard average or maximum operations, you create a custom aggregate method to compute a single value from a sequence of values. You also create a method that works as a custom filter or a specific data transform for a sequence of values and returns a new sequence. Examples of such methods are , , and . +Extend the set of methods that you use for LINQ queries by adding extension methods to the interface. For example, in addition to the standard average or maximum operations, you create a custom aggregate method to compute a single value from a sequence of values. You also create a method that works as a custom filter or a specific data transform for a sequence of values and returns a new sequence. Examples of such methods are , , and . -When you extend the interface, you can apply your custom methods to any enumerable collection. For more information, see [Extension Methods](../programming-guide/classes-and-structs/extension-methods.md). +When you extend the interface, you can apply your custom methods to any enumerable collection. For more information, see [Extension members](../programming-guide/classes-and-structs/extension-methods.md). -An *aggregate* method computes a single value from a set of values. LINQ provides several aggregate methods, including , , and . You can create your own aggregate method by adding an extension method to the interface. +An *aggregate* method computes a single value from a set of values. LINQ provides several aggregate methods, including , , and . Create your own aggregate method by adding an extension method to the interface. -Beginning in C# 14, you can declare an *extension block* to contain multiple extension members. You declare an extension block with the keyword `extension` followed by the receiver parameter in parentheses. The following code example shows how to create an extension method called `Median` in an extension block. The method computes a median for a sequence of numbers of type `double`. +Beginning in C# 14, you can declare an *extension block* to contain multiple extension members. Declare an extension block with the keyword `extension` followed by the receiver parameter in parentheses. The following code example shows how to create an extension method called `Median` in an extension block. The method computes a median for a sequence of numbers of type `double`. :::code language="csharp" source="./snippets/HowToExtend/ExtensionMembers.cs" ID="MedianExtensionMember"::: @@ -24,15 +25,15 @@ You can also add the `this` modifier to a static method to declare an *extension :::code language="csharp" source="./snippets/HowToExtend/LinqExtensions.cs" ID="LinqExtensionClass"::: -You call either extension method for any enumerable collection in the same way you call other aggregate methods from the interface. +Call either extension method for any enumerable collection in the same way you call other aggregate methods from the interface. The following code example shows how to use the `Median` method for an array of type `double`. :::code language="csharp" source="./snippets/HowToExtend/Program.cs" ID="MedianUsage"::: -You can *overload your aggregate method* so that it accepts sequences of various types. The standard approach is to create an overload for each type. Another approach is to create an overload that takes a generic type and convert it to a specific type by using a delegate. You can also combine both approaches. +*Overload your aggregate method* so that it accepts sequences of various types. The standard approach is to create an overload for each type. Another approach is to create an overload that takes a generic type and convert it to a specific type by using a delegate. You can also combine both approaches. -You can create a specific overload for each type that you want to support. The following code example shows an overload of the `Median` method for the `int` type. +Create a specific overload for each type that you want to support. The following code example shows an overload of the `Median` method for the `int` type. :::code language="csharp" source="./snippets/HowToExtend/LinqExtensions.cs" ID="IntOverload"::: @@ -46,26 +47,26 @@ The following code shows an overload of the `Median` method that takes the delegate parameter to the `Median` method for each case. :::code language="csharp" source="./snippets/HowToExtend/Program.cs" ID="GenericUsage"::: -You can extend the interface with a custom query method that returns a *sequence of values*. In this case, the method must return a collection of type . Such methods can be used to apply filters or data transforms to a sequence of values. +Extend the interface with a custom query method that returns a *sequence of values*. In this case, the method must return a collection of type . Such methods can be used to apply filters or data transforms to a sequence of values. The following example shows how to create an extension method named `AlternateElements` that returns every other element in a collection, starting from the first element. :::code language="csharp" source="./snippets/HowToExtend/LinqExtensions.cs" ID="SequenceElement"::: -You can call this extension method for any enumerable collection just as you would call other methods from the interface, as shown in the following code: +Call this extension method for any enumerable collection just as you would call other methods from the interface, as shown in the following code: :::code language="csharp" source="./snippets/HowToExtend/Program.cs" ID="SequenceUsage"::: -Each example shown in this article has a different *receiver*. That means each method must be declared in a different extension block that specifies the unique receiver. The following code example shows a single static class with three different extension blocks, each of which contains one of the methods defined in this article: +Each example shown in this article has a different *receiver*. That means you must declare each method in a different extension block that specifies the unique receiver. The following code example shows a single static class with three different extension blocks, each of which contains one of the methods defined in this article: :::code language="csharp" source="./snippets/HowToExtend/ExtensionMembers.cs" ID="ExtensionMemberClass"::: The final extension block declares a generic extension block. The type parameter for the receiver is declared on the `extension` itself. -The preceding example declares one extension member in each extension block. In most cases, you create multiple extension members for the same receiver. In those cases, you should declare the extensions for those members in a single extension block. +The preceding example declares one extension member in each extension block. In most cases, you create multiple extension members for the same receiver. In those cases, declare the extensions for those members in a single extension block. diff --git a/docs/csharp/linq/index.md b/docs/csharp/linq/index.md index 87d3628bb1038..77ec4ab178ecf 100644 --- a/docs/csharp/linq/index.md +++ b/docs/csharp/linq/index.md @@ -2,13 +2,14 @@ title: Language Integrated Query (LINQ) description: Introduces Language Integrated Query (LINQ) in C#. ms.topic: concept-article -ms.date: 08/08/2025 +ms.date: 12/01/2025 +ai-usage: ai-assisted --- # Language Integrated Query (LINQ) Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language. Traditionally, queries against data are expressed as simple strings without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query language for each type of data source: SQL databases, XML documents, various Web services, and so on. With LINQ, a query is a first-class language construct, just like classes, methods, and events. -When you write queries, the most visible "language-integrated" part of LINQ is the query expression. Query expressions are written in a declarative *query syntax*. By using query syntax, you perform filtering, ordering, and grouping operations on data sources with a minimum of code. You use the same query expression patterns to query and transform data from any type of data source. +When you write queries, the most visible "language-integrated" part of LINQ is the query expression. You write query expressions in a declarative *query syntax*. By using query syntax, you perform filtering, ordering, and grouping operations on data sources with a minimum of code. You use the same query expression patterns to query and transform data from any type of data source. The following example shows a complete query operation. The complete operation includes creating a data source, defining the query expression, and executing the query in a [`foreach`](../language-reference/statements/iteration-statements.md#the-foreach-statement) statement. @@ -18,31 +19,30 @@ You might need to add a [`using`](../language-reference/keywords/using-directive ## Query expression overview -- Query expressions query and transform data from any LINQ-enabled data source. For example, a single query can retrieve data from an SQL database and produce an XML stream as output. +- Query expressions examine and transform data from any LINQ-enabled data source. For example, a single query can retrieve data from a SQL database and produce an XML stream as output. - Query expressions use many familiar C# language constructs, which make them easy to read. - The variables in a query expression are all strongly typed. - A query isn't executed until you iterate over the query variable, for example in a `foreach` statement. -- At compile time, query expressions are converted to standard query operator method calls according to the rules defined in the C# specification. Any query that can be expressed by using query syntax can also be expressed by using method syntax. In some cases, query syntax is more readable and concise. In others, method syntax is more readable. There's no semantic or performance difference between the two different forms. For more information, see [C# language specification](~/_csharpstandard/standard/expressions.md#1222-query-expressions) and [Standard query operators overview](standard-query-operators/index.md). -- Some query operations, such as or , have no equivalent query expression clause and must therefore be expressed as a method call. Method syntax can be combined with query syntax in various ways. -- Query expressions can be compiled to expression trees or to delegates, depending on the type that the query is applied to. queries are compiled to delegates. and queries are compiled to expression trees. For more information, see [Expression trees](/dotnet/csharp/advanced-topics/expression-trees). +- At compile time, the compiler converts query expressions to standard query operator method calls according to the rules defined in the C# specification. You can express any query that uses query syntax by using method syntax. In some cases, query syntax is more readable and concise. In others, method syntax is more readable. There's no semantic or performance difference between the two different forms. For more information, see [C# language specification](~/_csharpstandard/standard/expressions.md#1222-query-expressions) and [Standard query operators overview](standard-query-operators/index.md). +- Some query operations, such as or , have no equivalent query expression clause and must be expressed as a method call. You can combine method syntax with query syntax in various ways. +- Query expressions can be compiled to expression trees or to delegates, depending on the type that the query is applied to. The compiler compiles queries to delegates. The compiler compiles and queries to expression trees. For more information, see [Expression trees](/dotnet/csharp/advanced-topics/expression-trees). ## How to enable LINQ querying of your data source ### In-memory data - There are two ways you enable LINQ querying of in-memory data. If the data is of a type that implements , you query the data by using LINQ to Objects. If it doesn't make sense to enable enumeration by implementing the interface, you define LINQ standard query operator methods, either in that type or as [extension methods](../programming-guide/classes-and-structs/extension-methods.md) for that type. Custom implementations of the standard query operators should use deferred execution to return the results. +You can enable LINQ querying of in-memory data in two ways. If the data is of a type that implements , query the data by using LINQ to Objects. If it doesn't make sense to enable enumeration by implementing the interface, define LINQ standard query operator methods either in that type or as [extension members](../programming-guide/classes-and-structs/extension-methods.md) for that type. Custom implementations of the standard query operators should use deferred execution to return the results. ### Remote data - The best option for enabling LINQ querying of a remote data source is to implement the interface. +The best option for enabling LINQ querying of a remote data source is to implement the interface. ## IQueryable LINQ providers - LINQ providers that implement can vary widely in their complexity. +LINQ providers that implement can vary widely in their complexity. - A less complex `IQueryable` provider might access a single method from a Web service. This type of provider is specific to the data source because it expects specific information in the queries that it handles. It has a closed type system, perhaps exposing a single result type. Most of the execution of the query occurs locally, for example by using the implementations of the standard query operators. A less complex provider might examine only one method call expression in the expression tree that represents the query, and let the remaining logic of the query be handled elsewhere. +A less complex `IQueryable` provider might access a single method from a Web service. This type of provider is specific to the data source because it expects specific information in the queries that it handles. It has a closed type system, perhaps exposing a single result type. Most of the execution of the query occurs locally, for example by using the implementations of the standard query operators. A less complex provider might examine only one method call expression in the expression tree that represents the query and let the remaining logic of the query be handled elsewhere. - An `IQueryable` provider of medium complexity might target a data source that has a partially expressive query language. If it targets a Web service, it might access more than one method of the Web service and select which method to call based on the information that the query seeks. A provider of medium complexity would have a richer type system than a simple provider, but it would still be a fixed type system. For example, the provider might expose types that have one-to-many relationships that can be traversed, but it wouldn't provide mapping technology for user-defined types. +An `IQueryable` provider of medium complexity might target a data source that has a partially expressive query language. If it targets a Web service, it might access more than one method of the Web service and select which method to call based on the information that the query seeks. A provider of medium complexity has a richer type system than a simple provider, but it's still a fixed type system. For example, the provider might expose types that have one-to-many relationships that can be traversed, but it doesn't provide mapping technology for user-defined types. - A complex `IQueryable` provider, such as the [Entity Framework Core](/ef/core/) provider, might translate complete LINQ queries to an expressive query language, such as SQL. A complex provider is more general because it can handle a wider variety of questions in the query. It also has an open type system and therefore must contain extensive infrastructure to map user-defined types. Developing a complex provider requires a significant amount of effort. - \ No newline at end of file +A complex `IQueryable` provider, such as the [Entity Framework Core](/ef/core/) provider, might translate complete LINQ queries to an expressive query language, such as SQL. A complex provider is more general because it can handle a wider variety of questions in the query. It also has an open type system and therefore must contain extensive infrastructure to map user-defined types. Developing a complex provider requires a significant amount of effort. diff --git a/docs/csharp/linq/standard-query-operators/index.md b/docs/csharp/linq/standard-query-operators/index.md index c4220d9eb4ce4..3e71d7bfb3136 100644 --- a/docs/csharp/linq/standard-query-operators/index.md +++ b/docs/csharp/linq/standard-query-operators/index.md @@ -1,15 +1,16 @@ --- -title: "Standard Query Operators Overview" +title: "Standard query operators overview" description: The LINQ standard query operators provide query capabilities including filtering, projection, aggregation, and sorting in C#. -ms.date: 05/29/2024 +ms.date: 12/01/2025 +ai-usage: ai-assisted --- -# Standard Query Operators Overview +# Standard query operators overview -The *standard query operators* are the keywords and methods that form the LINQ pattern. The C# language defines [LINQ query keywords](../../language-reference/keywords/query-keywords.md) that you use for the most common query expression. The compiler translates expressions using these keywords to the equivalent method calls. The two forms are synonymous. Other methods that are part of the namespace don't have equivalent query keywords. In those cases, you must use the method syntax. This section covers all the query operator keywords. The runtime and other NuGet packages add more methods designed to work with LINQ queries each release. The most common methods, including those that have query keyword equivalents are covered in this section. For the full list of query methods supported by the .NET Runtime, see the API documentation. In addition to the methods covered here, this class contains methods for concatenating data sources, computing a single value from a data source, such as a sum, average, or other value. +The *standard query operators* are the keywords and methods that form the LINQ pattern. The C# language defines [LINQ query keywords](../../language-reference/keywords/query-keywords.md) that you use for the most common query expression. The compiler translates expressions using these keywords to the equivalent method calls. The two forms are synonymous. Other methods that are part of the namespace don't have equivalent query keywords. In those cases, you must use the method syntax. This section covers all the query operator keywords. The runtime and other NuGet packages add more methods designed to work with LINQ queries each release. The most common methods, including those methods that have query keyword equivalents, are covered in this section. For the full list of query methods supported by the .NET Runtime, see the API documentation. In addition to the methods covered here, this class contains methods for concatenating data sources, computing a single value from a data source, such as a sum, average, or other value. [!INCLUDE [Prerequisites](../includes/linq-syntax.md)] -Most of these methods operate on sequences, where a sequence is an object whose type implements the interface or the interface. The standard query operators provide query capabilities including filtering, projection, aggregation, sorting and more. The methods that make up each set are static members of the and classes, respectively. They're defined as [*extension methods*](../../programming-guide/classes-and-structs/extension-methods.md) of the type that they operate on. +Most of these methods operate on sequences, where a sequence is an object whose type implements the interface or the interface. The standard query operators provide query capabilities including filtering, projection, aggregation, sorting, and more. The methods that make up each set are extension members defined in the and classes, respectively. They're defined as [*extension members*](../../programming-guide/classes-and-structs/extension-methods.md) where the receiver type is the `IEnumerable` and `IQueryable` type that they operate on. The distinction between and sequences determines how the query is executed at runtime. @@ -17,7 +18,7 @@ For `IEnumerable`, the returned enumerable object captures the arguments that For `IQueryable`, the query is translated into an [expression tree](../../advanced-topics/expression-trees/index.md). The expression tree can be translated to a native query when the data source can optimize the query. Libraries such as [Entity Framework](/ef/core/) translate LINQ queries into native SQL queries that execute at the database. -The following code example demonstrates how the standard query operators can be used to obtain information about a sequence. +The following code example demonstrates how you can use the standard query operators to obtain information about a sequence. :::code language="csharp" source="./snippets/standard-query-operators/IndexExamples.cs" id="FirstSentence"::: @@ -25,13 +26,13 @@ Where possible, the queries in this section use a sequence of words or numbers a :::code language="csharp" source="./snippets/standard-query-operators/DataSources.cs" id="QueryDataSource"::: -Each `Student` has a grade level, a primary department, and a series of scores. A `Teacher` also has a `City` property that identifies the campus where the teacher holds classes. A `Department` has a name, and a reference to a `Teacher` who serves as the department head. +Each `Student` has a grade level, a primary department, and a series of scores. A `Teacher` also has a `City` property that identifies the campus where the teacher holds classes. A `Department` has a name and a reference to a `Teacher` who serves as the department head. You can find the data set in the [source repo](https://github.com/dotnet/docs/blob/main/docs/csharp/linq/standard-query-operators/snippets/standard-query-operators/DataSources.cs#L41). ## Types of query operators -The standard query operators differ in the timing of their execution, depending on whether they return a singleton value or a sequence of values. Those methods that return a singleton value (such as and ) execute immediately. Methods that return a sequence defer the query execution and return an enumerable object. You can use the output sequence of one query as the input sequence to another query. Calls to query methods can be chained together in one query, which enables queries to become arbitrarily complex. +The standard query operators differ in the timing of their execution, depending on whether they return a singleton value or a sequence of values. Those methods that return a singleton value (such as and ) execute immediately. Methods that return a sequence defer the query execution and return an enumerable object. You can use the output sequence of one query as the input sequence to another query. You can chain calls to query methods together in one query, which enables queries to become arbitrarily complex. ## Query operators @@ -42,7 +43,7 @@ In a LINQ query, the first step is to specify the data source. In a LINQ query, The range variable is like the iteration variable in a `foreach` loop except that no actual iteration occurs in a query expression. When the query is executed, the range variable serves as a reference to each successive element in `students`. Because the compiler can infer the type of `student`, you don't have to specify it explicitly. You can introduce more range variables in a `let` clause. For more information, see [let clause](../../language-reference/keywords/let-clause.md). > [!NOTE] -> For non-generic data sources such as , the range variable must be explicitly typed. For more information, see [How to query an ArrayList with LINQ (C#)](../how-to-query-collections.md) and [from clause](../../language-reference/keywords/from-clause.md). +> For non-generic data sources such as , you must explicitly type the range variable. For more information, see [How to query an ArrayList with LINQ (C#)](../how-to-query-collections.md) and [from clause](../../language-reference/keywords/from-clause.md). Once you obtain a data source, you can perform any number of operations on that data source: @@ -52,7 +53,7 @@ Once you obtain a data source, you can perform any number of operations on that - [Join data](join-operations.md) using the `join` keyword. - [Project data](projection-operations.md) using the `select` keyword. -## Query Expression Syntax Table +## Query expression syntax table The following table lists the standard query operators that have equivalent query expression clauses. @@ -70,7 +71,7 @@ The following table lists the standard query operators that have equivalent quer ||`orderby …, … descending`

(For more information, see [orderby clause](../../language-reference/keywords/orderby-clause.md).)| ||`where`

(For more information, see [where clause](../../language-reference/keywords/where-clause.md).)| -## Data Transformations with LINQ +## Data transformations with LINQ Language-Integrated Query (LINQ) isn't only about retrieving data. It's also a powerful tool for transforming data. By using a LINQ query, you can use a source sequence as input and modify it in many ways to create a new output sequence. You can modify the sequence itself without modifying the elements themselves by sorting and grouping. But perhaps the most powerful feature of LINQ queries is the ability to create new types. The [select](../../language-reference/keywords/select-clause.md) clause creates an output element from an input element. You use it to transform an input element into an output element: @@ -79,7 +80,7 @@ Language-Integrated Query (LINQ) isn't only about retrieving data. It's also a p - Create output sequences whose elements consist of the results of operations performed on the source data. - Create output sequences in a different format. For example, you can transform data from SQL rows or text files into XML. -These transformations can be combined in various ways in the same query. Furthermore, the output sequence of one query can be used as the input sequence for a new query. The following example transforms objects in an in-memory data structure into XML elements. +You can combine these transformations in various ways in the same query. Furthermore, you can use the output sequence of one query as the input sequence for a new query. The following example transforms objects in an in-memory data structure into XML elements. :::code language="csharp" source="./snippets/standard-query-operators/IndexExamples.cs" id="XmlTransformation"::: @@ -89,7 +90,7 @@ The code produces the following XML output: For more information, see [Creating XML Trees in C# (LINQ to XML)](../../../standard/linq/create-xml-trees.md). -You can use the results of one query as the data source for a subsequent query. This example shows how to order the results of a join operation. This query creates a group join, and then sorts the groups based on the `department` element, which is still in scope. Inside the anonymous type initializer, a subquery orders all the matching elements from the `students` sequence. +You can use the results of one query as the data source for a subsequent query. This example shows how to order the results of a join operation. This query creates a group join and then sorts the groups based on the `department` element, which is still in scope. Inside the anonymous type initializer, a subquery orders all the matching elements from the `students` sequence. :::code language="csharp" source="./snippets/standard-query-operators/OrderResultsOfJoin.cs" id="OrderResultsOfJoinQuery"::: @@ -97,13 +98,13 @@ The equivalent query using method syntax is shown in the following code: :::code language="csharp" source="./snippets/standard-query-operators/OrderResultsOfJoin.cs" id="OrderResultsOfJoinMethod"::: -Although you can use an `orderby` clause with one or more of the source sequences before the join, generally we don't recommend it. Some LINQ providers might not preserve that ordering after the join. For more information, see [join clause](../../language-reference/keywords/join-clause.md). +Although you can use an `orderby` clause with one or more of the source sequences before the join, we generally don't recommend it. Some LINQ providers might not preserve that ordering after the join. For more information, see [join clause](../../language-reference/keywords/join-clause.md). ## See also - - - [select clause](../../language-reference/keywords/select-clause.md) -- [Extension Methods](../../programming-guide/classes-and-structs/extension-methods.md) +- [Extension members](../../programming-guide/classes-and-structs/extension-methods.md) - [Query Keywords (LINQ)](../../language-reference/keywords/query-keywords.md) - [Anonymous Types](../../fundamentals/types/anonymous-types.md) From 7803b3b73aa1dd6445a05ba0b2f23d8941eea0ed Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 1 Dec 2025 17:15:23 -0500 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/csharp/linq/get-started/write-linq-queries.md | 2 +- docs/csharp/linq/standard-query-operators/index.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/csharp/linq/get-started/write-linq-queries.md b/docs/csharp/linq/get-started/write-linq-queries.md index 32031310d5105..5bddcef585301 100644 --- a/docs/csharp/linq/get-started/write-linq-queries.md +++ b/docs/csharp/linq/get-started/write-linq-queries.md @@ -45,7 +45,7 @@ Write most queries with *query syntax* to create *query expressions*. The follow :::code language="csharp" source="./snippets/SnippetApp/WriteLinqQueries.cs" id="write_linq_queries_1"::: -The type of the queries is . You can write all of these queries using [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) as shown in the following example: +The type of the queries is . All of these queries can be written using [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) as shown in the following example: `var query = from num in numbers...` diff --git a/docs/csharp/linq/standard-query-operators/index.md b/docs/csharp/linq/standard-query-operators/index.md index 3e71d7bfb3136..f22efbfd08f41 100644 --- a/docs/csharp/linq/standard-query-operators/index.md +++ b/docs/csharp/linq/standard-query-operators/index.md @@ -6,11 +6,11 @@ ai-usage: ai-assisted --- # Standard query operators overview -The *standard query operators* are the keywords and methods that form the LINQ pattern. The C# language defines [LINQ query keywords](../../language-reference/keywords/query-keywords.md) that you use for the most common query expression. The compiler translates expressions using these keywords to the equivalent method calls. The two forms are synonymous. Other methods that are part of the namespace don't have equivalent query keywords. In those cases, you must use the method syntax. This section covers all the query operator keywords. The runtime and other NuGet packages add more methods designed to work with LINQ queries each release. The most common methods, including those methods that have query keyword equivalents, are covered in this section. For the full list of query methods supported by the .NET Runtime, see the API documentation. In addition to the methods covered here, this class contains methods for concatenating data sources, computing a single value from a data source, such as a sum, average, or other value. +The *standard query operators* are the keywords and methods that form the LINQ pattern. The C# language defines [LINQ query keywords](../../language-reference/keywords/query-keywords.md) that you use for the most common query expression. The compiler translates expressions using these keywords to the equivalent method calls. The two forms are synonymous. Other methods that are part of the namespace don't have equivalent query keywords. In those cases, you must use the method syntax. This section covers all the query operator keywords. The runtime and other NuGet packages add more methods designed to work with LINQ queries each release. The most common methods, including those that have query keyword equivalents, are covered in this section. For the full list of query methods supported by the .NET Runtime, see the API documentation. In addition to the methods covered here, this class contains methods for concatenating data sources, computing a single value from a data source, such as a sum, average, or other value. [!INCLUDE [Prerequisites](../includes/linq-syntax.md)] -Most of these methods operate on sequences, where a sequence is an object whose type implements the interface or the interface. The standard query operators provide query capabilities including filtering, projection, aggregation, sorting, and more. The methods that make up each set are extension members defined in the and classes, respectively. They're defined as [*extension members*](../../programming-guide/classes-and-structs/extension-methods.md) where the receiver type is the `IEnumerable` and `IQueryable` type that they operate on. +Most of these methods operate on sequences, where a sequence is an object whose type implements the interface or the interface. The standard query operators provide query capabilities including filtering, projection, aggregation, sorting, and more. The methods that make up each set are extension members defined in the and classes, respectively. They're defined as [*extension members*](../../programming-guide/classes-and-structs/extension-methods.md) where the receiver type is either the `IEnumerable` or `IQueryable` type that they operate on. The distinction between and sequences determines how the query is executed at runtime. @@ -32,7 +32,7 @@ You can find the data set in the [source repo](https://github.com/dotnet/docs/bl ## Types of query operators -The standard query operators differ in the timing of their execution, depending on whether they return a singleton value or a sequence of values. Those methods that return a singleton value (such as and ) execute immediately. Methods that return a sequence defer the query execution and return an enumerable object. You can use the output sequence of one query as the input sequence to another query. You can chain calls to query methods together in one query, which enables queries to become arbitrarily complex. +The standard query operators differ in the timing of their execution, depending on whether they return a singleton value or a sequence of values. Those methods that return a singleton value (such as and ) execute immediately. Methods that return a sequence defer the query execution and return an enumerable object. You can use the output sequence of one query as the input sequence to another query. You chain query methods together in one query, which enables queries to become arbitrarily complex. ## Query operators From 14c415c8866dc08d065a58b61d1013a01839e995 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 1 Dec 2025 17:22:56 -0500 Subject: [PATCH 3/3] respond to feedback --- docs/csharp/linq/get-started/write-linq-queries.md | 2 +- docs/csharp/linq/standard-query-operators/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/linq/get-started/write-linq-queries.md b/docs/csharp/linq/get-started/write-linq-queries.md index 5bddcef585301..04261bf8bbe8a 100644 --- a/docs/csharp/linq/get-started/write-linq-queries.md +++ b/docs/csharp/linq/get-started/write-linq-queries.md @@ -6,7 +6,7 @@ ai-usage: ai-assisted --- # Write C# LINQ queries to query data -Most queries in the introductory Language Integrated Query (LINQ) documentation use the LINQ declarative query syntax. The C# compiler translates query syntax into method calls. These method calls implement the standard query operators and have names such as `Where`, `Select`, `GroupBy`, `Join`, `Max`, and `Average`. You can call them directly by using method syntax instead of query syntax. +Most queries in the introductory Language Integrated Query (LINQ) documentation use the LINQ declarative query syntax. The C# compiler translates query syntax into method calls. These method calls implement the standard query operators. They have names such as `Where`, `Select`, `GroupBy`, `Join`, `Max`, and `Average`. You call them directly by using method syntax instead of query syntax. Query syntax and method syntax are semantically identical, but query syntax is often simpler and easier to read. You must express some queries as method calls. For example, you must use a method call to express a query that retrieves the number of elements that match a specified condition. You also must use a method call for a query that retrieves the element that has the maximum value in a source sequence. The reference documentation for the standard query operators in the namespace generally uses method syntax. Become familiar with how to use method syntax in queries and in query expressions themselves. diff --git a/docs/csharp/linq/standard-query-operators/index.md b/docs/csharp/linq/standard-query-operators/index.md index f22efbfd08f41..aac0616c2d60c 100644 --- a/docs/csharp/linq/standard-query-operators/index.md +++ b/docs/csharp/linq/standard-query-operators/index.md @@ -80,7 +80,7 @@ Language-Integrated Query (LINQ) isn't only about retrieving data. It's also a p - Create output sequences whose elements consist of the results of operations performed on the source data. - Create output sequences in a different format. For example, you can transform data from SQL rows or text files into XML. -You can combine these transformations in various ways in the same query. Furthermore, you can use the output sequence of one query as the input sequence for a new query. The following example transforms objects in an in-memory data structure into XML elements. +You combine these transformations in various ways in the same query. Furthermore, you can use the output sequence of one query as the input sequence for a new query. The following example transforms objects in an in-memory data structure into XML elements. :::code language="csharp" source="./snippets/standard-query-operators/IndexExamples.cs" id="XmlTransformation":::