An introduction to LINQ

23 July 2012, by

previous article in series

This series of posts is about Language Integrated Query (LINQ, pronounced “link”) – a set of libraries providing a means of querying data in C#. It is intended very much as a beginner’s guide, although those who have a basic knowledge of LINQ but don’t have a full understanding of its principles might still find some points of interest.

It does require a small amount of knowledge of generics though – my introduction to the subject will do the trick if you’re unsure.

What is LINQ?

LINQ was released as part of the .NET Framework 3.5.  It includes:

  • Methods to do querying (e.g. a Where method)
  • Some special language syntax which allows you to write queries that look a bit like SQL
  • A number of different data sources, normally with their own subtle variants on the LINQ libraries (e.g. LINQ-to-SQL and LINQ-to-Entities, which provide ways of accessing a SQL database; LINQ-to-XML, which provides a LINQ-based way of querying an XML document; LINQ-to-Objects, which lets you use LINQ with normal C# data structures like arrays)

This article concentrates mostly on LINQ-to-Objects, and sticks largely with “traditional” C# syntax. You don’t need to be accessing a database and embed SQL-like statements in your C# code in order to make good use of LINQ. Indeed, almost any C# program could benefit from some of the techniques described here.

Simple queries in LINQ

Since LINQ is all about data querying, it makes sense to give an example of this type. So, to count how many nice beers are available:

using System.Linq;

public int CountNiceBeers()
  return GetBeerList().Where(beer => beer.IsNice).Count();

Key points to note:

  • Where is a method on IEnumerable<T>. Strictly speaking it’s an extension method, so you need the using statement or you’ll wonder where the Where method has disappeared to.
  • Where takes a function (strictly speaking, a Func<Beer, bool> in this case), which is what defines the filter criteria. In this case we’ve used an anonymous function (a lambda).
  • Where returns another IEnumerable<T>, which we then call the Count method on – again, Count is an extension method, and a part of the LINQ library.

Using a named method for the filter

Although the anonymous function is quite neat, and lets us avoid writing much code, it can sometimes be a good idea to extract this out into a method – this keeps things very explicit, and I’d often recommend it if the where clause were a bit more complicated:

public int CountNiceBeers()
  return GetBeerList().Where(BeerIsNice).Count();

private static bool BeerIsNice(Beer beer)
  return beer.IsNice;

Note however that you can’t make the above refactoring if you’re using something like LINQ-to-SQL – it will give you a runtime error. This is because LINQ-to-SQL needs to “understand” the where clause in order to efficiently execute it against your database – more details, and a solution, are available in Dan Corder’s post on Staying DRY with LINQ to Entities. But it’s fine when you’re using LINQ-to-Objects.

An alternative query syntax

As an aside, here’s another way to write the CountNiceBeers method, using the alternative syntax that LINQ provides:

public int CountNiceBeersAgain()
  var niceBeers = from beer in GetBeerList()
                   where beer.IsNice
                   select beer;

  return niceBeers.Count();

Personally, I find this syntax rather ugly, and liable to be horribly misused. To be fair it is occasionally a neater way to express what you’re saying than using the traditional approach. But that’s quite rare, so I’m not going to talk about it again. Not everyone would agree with me!

More complex queries

LINQ has all the operators you’d expect to find for querying data, so here’s a contrived example to give you a flavour of what’s out there:

public IEnumerable<string> GetSomeContrivedBeers()
  return GetBeerList().
    Where(beer => beer.IsNice).
    OrderByDescending(beer => beer.Name).
    Select(beer => beer.Name);

This filters to get only the nice beer, then reverse orders by name of the beer, then picks just the first five beers, and selects out the names to return.

Select is most often used in LINQ examples as a counterpart to the SELECT statement in SQL. And it is, but it’s often more helpful to see Select as a sort of conversion operation. It basically maps from an IEnumerable<Something> to an IEnumerable<SomethingElse>, via a function of your choice which takes a single Something and converts that to a SomethingElse.  In the above example, we’re converting Beers to strings.

(If you’re actually just casting from one type to another, use GetBeerList().Cast<Beverage>() rather than GetBeerList().Select(beer => (Beverage)beer) – best to be explicit about what you’re doing)

Next time, I’ll look at how to use LINQ to simplify your code.

next article in series

Tags: , ,

Categories: Technical


Leave a Reply

* Mandatory fields

seven − = 0

Submit Comment