LINQ: Language Integrated Query, isa set of language and framework features for writing structured type-safequeries over local object collections and remote data sources, introduced in C#3.0 FM 3.5.
LINQ enables to query any collectionimplementing IEnumerable<T>. LINQ offers the benefits of bothcompile-time type checking and dynamic query composition.
All core types are defined in theSystem.Linq and System.Linq.Expressions namespaces.
Getting Started
The basic units of data in LINQ aresequences and elements.
Sequence: any object that implementsIEnumerable<T>
Element: each item in the sequence.
Local sequence: represent a localcollection of objects in memory.
Query: an expression that transformssequences with query operators
Queries that operates over localsequences are called local queries or LINQ-to-objects queries
Query operator: a method thattransforms a sequence. A typical query operator accepts an input sequence andemits a transformed output sequence. Standard query operator: static extensionmethods
Most query operators accept a lambdaexpression as an argument. The lambda expression helps guide and shape thequery.
Fluent Syntax
Fluent syntax is the most flexibleand fundamental.
Chaining Query Operators
Data flows from left to rightthrough the chain of operators.
A query operator never alters theinput sequence, it returns a new sequence. The output sequence of one operatoris the input sequence of the next.
Withoutextension methods, the query loses its fluency:
IEnumerable<string> query = Enumerable.Select (Enumerable.Where( names, n => n.Contains(“a”) ), n => n.ToUpper() );
Composing Lambda Expressions
An expression returning a bool valueis called a predicate.
A lambda expression in a queryoperator always works on individual elements in the input sequence, not thesequence as a whole.
Then standard query operatorsutilize generic Func delegates. Func is a family of general-purpose genericdelegates in System.Linq, defined with the following intent: The type argumentsin Func appear in the same order they do in lambda expressions.
Func<TSource, TResult>:TSource => TResult
The compiler infers the type ofTResult from the return value of the lambda expression. For Where, input andoutput elements are of the same type.
Natural Ordering
The original ordering of elementswithin an input sequence is significant in LINQ. Some query operators rely onthis behavior, such as Take, Skip and Reverse.
The Take operator outputs the firstx elements, discarding the rest.
The Skip operator ignores the firstx elements and outputs the rest.
LINQ preserves the ordering ofelements in the input sequence wherever possible.
Other Operators
Not all query return a sequence: Theymust appear as the last operators on the result, they don’t return acollection. Element operators First, Last, ElementAt extract one element;Aggregation operators Count, Min return a scalar value, usually of numerictype; Quantifiers Contains, Any return a bool value.
Some query operators accept twoinput sequences: Concat, Union (with duplicates removed)
Query Expressions
Query expressions: based on listcomprehensions from functional programming languages, not on SQL.
Query expressions always start witha from clause and ends with either a select or group clause. The from clausedeclares a range variable, rather like foreach.
The compiler processes a queryexpression by translating it into fluent syntax. Anything written in querysyntax can be written in fluent syntax.
Query expressions cannot compileunless you import a namespace, or write an instance method for every queryoperator.
Range Variables
Rang variable: the identifierimmediately following the from keyword syntax, refers to the current element inthe sequence that the operation is to be performed on.
Query expressions also let you introduce newrange variables via let, into or an additional from clause.
Query Syntax vs. SQL Syntax
They are very different. A LINQquery is a C# expression, follows standard C# rules: can’t use a variablebefore declaration; dataflow left to right; a conveyor belt or pipeline ofoperators that accept and emit ordered sequences.
Query Syntax vs. Fluent Syntax
Query and fluent syntax each haveadvantages.
Query syntax for queries that:
Alet clause for introducing a new variable alongside the range variable
SelectMany,Join or GroupJoin, followed by an outer range variable reference
Fluent syntax:
Queriesthat comprise a single operator
Anyoperator except: Where, Select, SelectMany, OrderBy, ThenBy, OrderByDescending,ThenByDescending, GroupBy, Join, GroupJoin require fluent syntax, at least inpart. They have no keyword in query syntax.
Mixed Syntax Queries
If a query operator has noquery-syntax support, you can mix query syntax and fluent syntax. The onlyrestriction is that each query-syntax component must be complete(from…select/group).
Deferred Execution
An important feature of most queryoperators is that they execute not when constructed, but when enumerated – whenMoveNext is called (foreach). This is called deferred or lazy execution.
All standard query operators providedeferred execution, except: Operators that return a single element or scalarvalue, such as First or Count; Conversion operators as ToArray, ToList,ToDictionary, ToLookup. These operators cause immediate query execution.
Deferred execution is importantbecause it decouples query construction from query execution, allowingconstructing a query in several steps.
Reevaluation
A deferred execution query isreevaluated when re-enumerate. We can defeat reevaluation by calling aconversion operator, such as ToArray or ToList. ToArray copies the output of aquery to an array, ToList to a generic List<>.
Captured Variables
Deferred execution has a sinistereffect. If the query’s lambda expressions referencelocal variables, these variables are captured variables. Captured variables are evaluated when the delegate isactually invoked (调用), not when the variables were captured. If you later change their value, thequery changes as well.
Don’tunderstand!!!!!
How Deferred Execution Works
Query operators provide deferredexecution by returning decorator sequences. A decorator sequence has no backingstructure of its own to store elements. Instead, it wraps another sequence thatyou supply at runtime, to which it maintains a permanent dependency. Wheneveryou request data from a decorator, it in turn must request data from thewrapped input sequence.
Calling Where merely constructs thedecorator wrapper sequence, holding a reference to the input sequence. Theinput sequence is enumerated only when the decorator is enumerated.
To write own query operator is justimplementing a decorator sequence.
Chaining Decorators
Chaining query operators create alayering of decorators. Each query operator instantiates a new decorator thatwraps the previous sequence. The model of chaining decorators is fully constructedprior to any enumeration.
Adding ToList onto the end of thequery would cause the preceding operators to execute right away.
How Queries Are Executed
LINQ query is a lazy productionline, where the conveyor belts roll elements only upon demand. Constructing aquery constructs a production line, with everything in place but with nothingrolling. Then when the consumer requests an element (enumerating), the rightmostconveyor belt activates; this in turn triggers the other to roll, when inputsequence elements are needed. LINQ follows a demand-driven pull model.
Subqueries
A subquery is a query containedwithin another query’s lambda expression. The rules for subqueries are aconsequence of the rules for lambda expressions and the behavior of queryoperators in general.
A subquery is privately scoped tothe enclosing expression and is able to reference the outer lambda argument (orrange variable in a query expression).