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+

Simple LINQ Queries

The second part of the LINQ to Objects tutorial describes basic querying using LINQ features. The article discusses the "Where" standard query operator, known as the restriction operator, and the equivalent query expression syntax.

Querying

Throughout the course of this tutorial the articles will follow a similar pattern. In each article I will introduce one or more of the standard query operators provided by LINQ. These will be described with example code that shows their usage. The article will then explain how the same, or similar, queries can be created using the query expression syntax. The basic LINQ to Objects functionality will be described in the early articles. Later instalments will build upon these foundations, adding new operators and techniques to allow the creation of complex queries.

In this article we will use the Where operator. This is also known as the restriction operator. It allows a collection of items to be filtered according to a Boolean condition, or predicate. The result of the operation is a collection containing all of the items that, when the predicate is applied, return a true result. Those that do not meet the condition are excluded from the results.

Where Operator

The Where operator is a standard query operator. As such, it is an extension method for collections that implement the generic IEnumerable<T> interface. When used as an extension method, one parameter is supplied. This is a Func delegate that accepts the predicate. Although any delegate with an appropriate signature can be supplied to the parameter, it is commonplace to use a lambda expression that returns a Boolean value. The lambda expression may then be applied to every item in the source data to determine which items should be included in the results and which should be omitted.

As with many standard query operators, the execution of the Where method is deferred, being executed "just-in-time". Usually this means that the predicate is evaluated for each item and the resultant collection is returned when it is first accessed. Until then, the result of the Where clause is an IEnumerable<T> that stores the information required to run the query but not the actual results.

The following code demonstrates the Where operator by executing a simple string query. First, an array of strings containing the colours of the rainbow is instantiated and initialised. This can be queried directly because all arrays implement IEnumerable<T>, with T being the array's type. The second line defines the query with a lambda expression specifying that only colours with five or more characters in the name will be included in the results. The results are then outputted to the console.

var colours = new string[] { "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet" };

var longNames = colours.Where(c => c.Length >= 5);

foreach(string s in longNames)
{
    Console.WriteLine(s);
}

/* OUTPUT

Orange
Yellow
Green
Indigo
Violet

*/

The type to use in the lambda expression is inferred from its usage, hence the Length property being available in the previous example. This means that you can query a collection of any type and access all of the methods, properties and public fields provided by the class or structure. We can demonstrate further with an example that queries a collection that holds objects of a custom class. First, we need to create the type. The following code creates an Employee class that holds the name, title and salary of a single employee in three properties. The class includes a constructor that allows each of these properties to be set. It also overrides the ToString method to simplify output of query results.

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);
    }
}

With the class created we can provide some sample data in a collection. In this example we will use a generic list instead of an array. The list holds data for four employees.

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)
};

As a simple example, we may wish to obtain a list of employees that are developers. These are those with the word "Developer" in their job title. This is easy to achieve using the Title property and the Contains method, which is a member of the string class. The following query should return Bob, Sam and Mel in the results. Jim is excluded.

var developers = employees.Where(e => e.Title.Contains("Developer"));

For more complex queries you can add to the predicate using the C# Boolean operators. The next example uses a combination of the AND and OR operators. It returns all developers with a salary greater than £35,000 and all non-developers with a salary lower than £25,000. The results include Bob and Jim only.

var developers = employees.Where(
    e => (e.Title.Contains("Developer") && e.Salary > 35000)
      || (!e.Title.Contains("Developer") && e.Salary < 25000));
21 June 2010