This chapter is about Language Integrated Query (LINQ), a set of language extensions that add the ability to work with sequences of items and then filter, sort, and project them into different outputs.
This chapter covers the following topics:
Although we wrote a few LINQ queries in Chapter 8, Working with Databases Using the Entity Framework Core, I didn't properly explain how LINQ works.
LINQ has several parts; some are required and some are optional:
Where
, OrderBy
, Select
, and so on. These are what provide the functionality of LINQ.from
, in
, where
, orderby
, descending
, select
, and so on. These are C# keywords that are an alias for some of the LINQ extension methods, and their use can simplify the queries you write, especially if you already have experience with other query languages, such as Structured Query Language (SQL).The extension methods, such as Where
and Select
, are appended by the Enumerable
static class to any type, known as a sequence, that implements IEnumerable<T>
.
For example, an array of any type automatically implements the IEnumerable<T>
class, where T
is the type of item in the array, so all arrays support LINQ to query and manipulate them.
All generic collections, such as List<T>
, Dictionary<TKey, TValue>
, Stack<T>
, and Queue<T>
, implement IEnumerable<T>
so they can be queried and manipulated with LINQ.
The most common reason for using LINQ is to filter items in a sequence using the Where
extension method.
In Visual Studio 2017, press Ctrl + Shift + N or navigate to File | New | Project.... In the New Project dialog, in the Installed | Templates list, expand Visual C#, and select .NET Core. In the list at the center, select Console App (.NET Core), type the name Ch09_LinqToObjects
, change the location to C:Code
, type the solution name Chapter09
, and then click on OK.
In Visual Studio Code, make a directory named Chapter09
with a subfolder named Ch09_LinqToObjects
. Open the Ch09_LinqToObjects
folder and execute the dotnet new console
command in the Terminal.
In the Main
method, add the following statements:
var names = new string[] { "Michael", "Pam", "Jim", "Dwight", "Angela", "Kevin", "Toby", "Creed" }; var query = names.Where(
As you type the Where
method, note that it is missing from the IntelliSense list of members of a string
array, as shown in the following screenshot:
This is because the Where
method is an extension method. It does not exist on the array type. It exists in a separate assembly and namespace. To make the Where
extension method available, we must import the System.Linq
namespace.
Add the following statement to the top of the Program.cs
file:
using System.Linq;
Now, as you type the open parenthesis after Where
, note the IntelliSense. It tells us that to call Where
, we must pass in an instance of a Func<string, bool>
delegate. This delegate must target a method with a matching signature:
Enter the following code to create a new delegate instance:
var query = names.Where(new Func<string, bool>())
Note the IntelliSense shown in Visual Studio 2017 (but not in Visual Studio Code). This tells us that the target
method must have a single input parameter of type string
, and a return of type bool
, as shown in the following screenshot:
For each string
variable passed to the method, the method must return a Boolean value. If the method returns true
, it indicates that we should include the string
in the results, and if the method returns false
, it indicates that we should exclude it.
Let's define a method that only includes names that are longer than four characters.
Add the following method under the Main
method:
static bool NameLongerThanFour(string name) { return name.Length > 4; }
Modify the Where
call and loop through the query items, as shown in the following code:
var query = names.Where( new Func<string, bool>(NameLongerThanFour)); foreach (var item in query) { WriteLine(item); }
In Visual Studio 2017, run the console application by pressing Ctrl + F5.
In Visual Studio Code, run the console application by entering dotnet run
.
View the following output:
Michael Dwight Angela Kevin Creed
We can simplify the code by deleting the explicit instantiation of the Func<string, bool>
delegate. The C# compiler will instantiate the Func<string, bool>
delegate for us, so you never need to explicitly do it.
Modify the query to look like this:
var query = names.Where(NameLongerThanFour);
Rerun the application and note that it has the same behavior.
We can simplify our code even further using a lambda expression in place of the named method.
Although it can look complicated at first, a lambda expression is simply a nameless function. It uses the =>
(read as "goes to") symbol to indicate the return value.
Modify the query to look like the following statement:
var query = names.Where(name => name.Length > 4);
Note that the syntax for a lambda expression includes all the important parts of the NameLongerThanFour
method, but nothing more. A lambda expression only needs to define the following:
The type of the name
input parameter is inferred from the fact that the sequence contains string
values, and the return type must be a bool
value for Where
to work, so the expression after the =>
symbol must return a bool
value.
The compiler does most of the work for us, so our code can be as concise as possible.
Rerun the application and note that it has the same behavior.
Where
is just one of about 30 extension methods provided by the Enumerable
type. Extension methods can be chained if the previous method returns another sequence, that is, a type that implements the IEnumerable<T>
class.
Append a call to OrderBy
to the end of the existing query, as shown here:
var query = names
.Where(name => name.Length > 4)
.OrderBy(name => name.Length);
Rerun the application and note that the names are now sorted with shortest first:
Kevin Creed Dwight Angela Michael
We might want to sort by more than one property.
Append a call to ThenBy
to the end of the existing query, as shown here:
var query = names
.Where(name => name.Length > 4)
.OrderBy(name => name.Length)
.ThenBy(name => name);
Rerun the application and note the slight difference in the following sort order. Within a group of names of the same length, the names are sorted alphabetically by the full value of the string, so Creed
comes before Kevin
, and Angela
comes before Dwight
:
Creed Kevin Angela Dwight Michael
18.225.55.193