BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

LINQ
.NET 3.5+

LINQ Projection

The third part of the LINQ to Objects tutorial describes basic projection in LINQ using the Select standard query operator and the select clause. These allow the type of all of the values that are returned from a LINQ query to be specified.

Projection

In the first two parts of the LINQ to Objects Tutorial, we have seen queries executed using the standard query operators and query expression syntax. All of the queries so far have extracted values or objects from a type-safe collection and returned a generic IEnumerable of the same class or structure. This can often be the required functionality but sometimes you will wish to return values of an alternative type.

The process of transforming the results of a query is called projection. You can project the results of a query after any filters have been applied to change the type of the collection that is returned. For example, you can select a single property or field from the source data or project multiple properties into an anonymous type. You can also add calculations and other operations to the projection to generate information that is based upon the source data but not directly retrieved from it.

In this article we will see examples of projection using the Select standard query operator and the select clause. These give a single result for each item in the source data. You can also perform projection over multiple source collections in one-to-many relationships, flattening the hierarchy into a single set of results. This will be examined in the next article in the tutorial.

Select Operator

The Select standard query operator is an extension method of the IEnumerable<T> interface that requires a single parameter containing a Func delegate. The delegate is applied to each result of the overall query to project each item to the required type. To demonstrate the operator we need some sample data to work with. First, we will create a class that represents an employee. This is the same class that we used in the previous article:

public class Employee
{
    public string Name { get; set; }
    public string Title { get; set; }
    public int Salary { get; set; }

    public Employee(string name, string title, int salary)
    {
        Name = name;
        Title = title;
        Salary = salary;
    }

    public override string ToString()
    {
        return string.Format("{0}, {1} (£{2})", Name, Title, Salary);
    }
}

We can now create a collection of employees to query:

var employees = new List<Employee>
{
    new Employee("Bob", "Senior Developer", 40000),
    new Employee("Sam", "Developer", 32000),
    new Employee("Mel", "Developer", 29000),
    new Employee("Jim", "Junior Programmer", 20000)
};

Simple Projection

For the first projection example, we will retrieve every item from the employees list. Instead of returning the entire employee object in each case, we will use a projection that extracts only the employees' names. This is achieved by using the Select operator with a Func delegate that returns the Name property of an employee, in this case defined using the lambda expression, "e => e.Name".

var names = employees.Select(e => e.Name);

/* RESULTS

Bob
Sam
Mel
Jim

*/

The Select operator can be combined with other standard query operators by chaining the methods together. In the following example, the names of all employees with a salary of more than £30,000 are included in the results. As with other operators that we have seen in the tutorial, the Select operator uses deferred execution. This means that the effects of the Where and Select operators are combined and executed as a single query when the results are first examined.

var names = employees.Where(e => e.Salary > 30000).Select(e => e.Name);

/* RESULTS

Bob
Sam

*/

Projecting into Anonymous Types

When you wish to obtain more than one field or property from a source collection it is common to project into an anonymous type. You can do this by using a delegate that returns an anonymous type and ensuring that the results of the query are assigned to an implicitly typed variable.

The following code shows a simple example. In this case the name and title for each result is combined into an anonymous type.

var namesAndTitles = employees.Select(e => new { e.Name, e.Title });

/* RESULTS

{ Name = Bob, Title = Senior Developer }
{ Name = Sam, Title = Developer }
{ Name = Mel, Title = Developer }
{ Name = Jim, Title = Junior Programmer }

*/

As you may expect, you can also assign names to the properties of the anonymous type by providing them within the braces following the new keyword. In the next sample, the names of the properties in the results are different to those in the source data:

var namesAndTitles = employees.Select(e => new { Employee = e.Name, Job = e.Title });

/* RESULTS

{ Employee = Bob, Job = Senior Developer }
{ Employee = Sam, Job = Developer }
{ Employee = Mel, Job = Developer }
{ Employee = Jim, Job = Junior Programmer }

*/

NB: Using similar code you can project into a collection of a known type, either by passing values to the constructor or by using object initializers.

5 July 2010