This is the second part of a series intended as an introduction to LINQ. The series should provide a good enough foundation to allow the uninitiated to begin using LINQ in a productive manner. In this post we’ll look at some of the common query methods in Enumerable and what LINQ looks like.
In the previous post we defined LINQ and discussed some of the features of the .NET Framework that make LINQ possible. This post will build upon that foundation. By the end of this post you should understand the basics of LINQ and understand how it can fit into your development toolbox.
Common Query Methods
The Enumerable class in the System.Linq namespace is central to LINQ’s functionality in that it defines all of the core extension methods that make up LINQ. There are tons of methods in the Enumerable class but for the purpose of this post we’ll focus on just a few. Most of the methods here have at least one overload. We’ll examine each method taking a more generalized approach to introduce the methods and divide them into a few categories.
Sequence Operations
The methods in this section work across an entire sequence.
Method Name | Description |
---|---|
Where | Primary method used to filter a sequence. |
Select | Primary method used to project results from the query |
Join | Allows combining sequences into a single query. Similar to a SQL join. |
OrderBy/OrderByDescending | Sorts a sequence. |
All | Indicates whether every element in a sequence meet the specified criteria. |
Any | Indicates whether any element in a sequence meet the specified criteria. |
Count | Gets the number of elements in a sequence. |
Element Retrieval Operations
Each of the methods below allow retrieval of a specific element in a sequence and have two forms. The basic form will throw an exception if the element cannot be found while the OrDefault version will return default(T).
Method Name | Description |
---|---|
First/FirstOrDefault | Retrieves the first element in a sequence. |
ElementAt/ElementAtOrDefault | Retrieves the element at the specified position in a sequence. |
Last/LastOrDefault | Retrieves the last element in a sequence. |
What Does LINQ Look Like?
LINQ statements can be written in either of two forms: query syntax and method (dot) syntax. While these forms are functionally equivalent they each have their place and the decision about which form to use will often come down to readability and is typically situational. There is no reason to use one form exclusively.
Each of the following examples will use a sequence that contains the first ten numbers in the Fibonacci sequence.
var fibonacci = new int[] { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
Where We’re Coming From
Before looking at each LINQ syntax it’s helpful to see an example of what LINQ aims to address. Consider the following code that builds a sequence of the even numbers found in the Fibonacci sequence defined above:
var evenNumbers = new List(); foreach(var i in fibonacci) { if(i % 2 == 0) { evenNumbers.Add(i); } }
This code, while not particularly complex involves a number of steps to accomplish a relatively simple task. First we define a List<int> to hold the even numbers. We then enter a loop where we check whether each value is even before adding it to the list. This is imperative programming at its finest. The focus of the code is on how rather than what. Of the eight lines of code only one line is really relevant to the problem of finding even numbers in the source sequence. LINQ addresses the imperative nature of this code by providing a functional framework to let us focus on the what rather than the how.
Method Syntax
Method syntax is a fluent interface that allows building queries using method calls. As its name implies, method syntax calls the LINQ extension methods directly passing lambda expressions as parameters. Compare the code below with the traditional example above.
var evenNumbers = fibonacci.Where(i => i % 2 == 0);
In this example we remove all of the imperative code and replace it with a single method call and let LINQ do all of the heavy lifting. When the Where method executes it calls the supplied lambda expression for each value in the source sequence. The lambda expression must return a boolean value that informs the Where method whether or not the current value meets the criteria.
Method syntax tends to be more readable for simple queries such as this example.
Query Syntax
Alternatively, query syntax introduces a SQL-like syntax for writing queries. Here is the same example repeated using query syntax:
var evenNumbers = from i in fibonacci where i % 2 == 0 select i;
Query syntax tends to be more verbose than method syntax but is well suited for composing more complex queries such as those that use joins.
Notice the SQL like structure of the above query. One important difference to note between SQL and query syntax is that the from and where clauses are in the opposite order as they would be in a SQL query. In fact, query syntax requires the from clause to appear first. By placing the from clause at the beginning of the query we get all of the benefits of IntelliSense within Visual Studio. Ultimately though, query syntax is just some syntactic sugar. When the code is compiled any queries using query syntax are parsed and converted to method syntax.
Next Steps
Now that we’ve seen some of the common LINQ methods and understand how to compose LINQ statements with both method and query syntax we can look at how to use the various methods. The next post will go in-depth showing how to compose LINQ statements using the common methods and introduce some new concepts such as deferred execution.
One comment
Comments are closed.