Before LINQ came out with C# 3.0, we wrote a LOT of code like this:
1public MyEmployeeList Method()
2{
3 MyEmployeeList aaEmployees = new MyEmployeeList();
4
5 foreach(var record in records)
6 {
7 if (record.Fields["GroupType"].Substring(0, 2) == "AA")
8 {
9 var newEmployee = new Employee();
10 newEmployee.Id = int.Parse(record.Fields["employee_id"].ToString());
11 newEmployee.FirstName = record.Fields["first_name"];
12 newEmployee.LastName = record.Fields["last_name"];
13
14 aaEmployees.AddEmployee(newEmployee);
15 }
16 }
17
18 return aaEmployees;
19}
Here's what's happening here:
Compare that code to this:
1return from record in records
2 where record.Fields["GroupType"].Substring(0, 2) == "AA"
3 select new Employee
4 {
5 Id = int.Parse(record.Fields["employee_id"].ToString()),
6 FirstName = record.Fields["first_name"],
7 LastName = record.Fields["last_name"]
8 };
A picky reader will observe that the return type is different between the two - the first returns a MyEmployeeList and the second an IEnumerable
LINQ is a set manipulation query language - it automates much of the grunt work and code that is common to software by making set operations generic.
We have been tasked with writing a business layer that will filter and organize a set of results returned from a query. The results have certain elements that need to be transformed, filtered, ordered, and grouped. It's important to understand that with LINQ, the results may have come from a database, they may have come from the file system, or by listening on a network socket, or they may be hard-coded. How the results got to us is largely immaterial - LINQ is designed to be utterly generic in how it performs the kind of set operations we're going to work with.
To begin with, we have a set of Employee objects, like the results of the query we looked at in the first section, but not filtered for having a group type beginning with AA. So our Employee object looks like this:
1public class Employee
2{
3 public string FirstName { get; set; }
4 public string LastName { get; set; }
5
6 public int Id { get; set; }
7
8 public string GroupCode { get; set; }
9
10 public List<string> Addresses { get; set; }
11}
Very simple. For the purposes of this guide, we're creating a set of three Employees with this code:
1List<Employee> employees = new List<Employee>
2{
3 new Employee { Id = 1, FirstName = "Chris", LastName = "Behrens", GroupCode = "AA123", Addresses = new List<string>{"7814 Vandalia Avenue Apt 3b Los Angeles CA 91610"} },
4 new Employee { Id = 2, FirstName = "Sam", LastName = "Smith", GroupCode = "AA128", Addresses = new List<string>{ "7814 Vandalia Avenue Apt 3b Los Angeles CA 91610" } },
5 new Employee { Id = 3, FirstName = "Gill", LastName = "Bates", GroupCode = "ZZ867", Addresses = new List<string>{"2810 Pisces Ct Albuequerque, NM 87144"} }
6};
And this set is contained in a List
1var employeeArray = (from e in employees
2select e).ToArray();
We always begin our LINQ statements with from - this defines the set we're working with and the variable we'll use for our set operations. Here, we're selecting the entire employee set, defining the set variable as
This is great, but now we have an array of Employee objects - we want a simpler array of ints containing only the ID. To narrow the scope of what is being selected, we select the ID property on our set variable
1var employeeIdArray = (from e in employees
2 select e.Id).ToArray();
As simple as that.
For the purposes of this guide, we're going to focus on the _fluent _syntax - the syntax which is close to T-SQL and English:
1var employeeIdArray = (from e in employees
2 select e.Id).ToArray();
In addition to the fluent syntax, you can also invoke LINQ as function calls, which are made available to set types as extension methods:
1var employeeIdArray = employees.Select(e => e.Id).ToArray();
In this case, we're expressing our set variable for our Select call as a lambda expression:
1.Select(e => e.Id)
Just like with the fluent syntax you get Intellisense for the members of the set variable as you type. You can mix these two syntaxes as well:
1var employeesAddresses = from e in employees select e.Addresses.First();
The .First() method does just what you think it does – it gets the first element in the list. This would return an IEnumerable of type string – the type of the addresses, and it would contain the first address listed for every employee in the employee set.