If you are familiar with SQL, you know how powerful a language it is. Using SQL, it's very easy to search for data without needing to pull all the data yourself and search manually.
But wouldn't it be cool if you could do an SQL statement on your in-memory System.Collections.Generic.List<BusinessObject> ?
C# 3.5 has brought this power to the developer in the form of LINQ. LINQ is short for Language Integrated Query.
LINQ is a sub-language to C# that allows the developer to query data and return custom results similar to SQL. This data can be on a SQL server as is done traditionally. However, part of the real power comes from using LINQ with C# in-memory objects. This is why I'm excited about it.
No longer do you need to create a custom search function for your custom data objects. It all can be done in "1 line" of C# code: filtering, ordering, etc.
For the remainder of this article, I will be using the following business object:
class BusinessObject
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
}
and I will have a System.Collections.Generic.List<BusinessObject> initialized as:
List<BusinessObject> list = new List<BusinessObject>();
list.Add(new BusinessObject() { Id = 0, Name = "Matt",
Age = 33, City = "Toronto" });
list.Add(new BusinessObject() { Id = 1, Name = "Jane",
Age = 25, City = "New York" });
list.Add(new BusinessObject() { Id = 2, Name = "Chris",
Age = 50, City = "London" });
list.Add(new BusinessObject() { Id = 3, Name = "Mary",
Age = 42, City = "Athens" });
list.Add(new BusinessObject() { Id = 4, Name = "John",
Age = 21, City = "Tokyo" });
list.Add(new BusinessObject() { Id = 5, Name = "Ruth",
Age = 77, City = "Rome" });
list.Add(new BusinessObject() { Id = 6, Name = "Bill",
Age = 65, City = "Sydney" });
If we want to get the records for everyone that lives in Tokyo, and then print out their names, we could do:
var results = from d in list
where d.City == "Tokyo"
select d;
foreach (var d in results)
Console.WriteLine("{0}", d.Name);
You'll notice that the result is in an anonymous type. I talked about anonymous types in a previous post. In this case, the anonymous type is a list of BusinessObjects.
In the above example, we're returning the entire record. If we wanted only the names of all people whose name starts with "M", we could do:
var results = from d in list
where d.Name[0] == 'M'
select d.Name;
foreach (var d in results)
Console.WriteLine("{0}", d);
[I am now half-way through writing this article and I've noticed that my C# syntax highlighter has not been updated for LINQ. I will have to search for a new one.]
LINQ can also order data in the result set. So if we wanted a list of everyone's name in alphabetical order that has retired, and convert their name to uppercase, we could do:
var results = from d in list
where d.Age >= 65
orderby d.Name
select new { Name = d.Name,
UpperName = d.Name.ToUpper() };
foreach (var d in results)
Console.WriteLine("{0} {1}", d.Name, d.UpperName);
This will sort the data and return back our filtered list of names. In this case, we created a new anonymous type for the returned data. We can refer to the named parameters later in this function. You'll notice that IntelliSense is smart enough to pick up on the anonymous types and auto-complete the member names. That's some pretty smart compiler work going on there.
LINQ can also do some other funky things in addition to data selection. If we wanted to sum everyone's age together, we could do:
int sum = (from d in list
select d.Age).Sum();
In one line of code, we're summing everyone's age instead of creating a temporary variable and looping though all the records.
LINQ has many more functions and features not covered by this article. As with SQL, your queries can get very complicated.
In this article, we're restricting ourself to querying against our in-memory data. LINQ can query against any IEnumerable<T> object. LINQ can also query directly against an SQL data set or an Xml file. The nice thing is that we could easily change our data source from an in-memory source to a real database and the source code would not change.
Here are some additional resources about LINQ.