Blog

Generic Lists in LINQ

Excerpt by Ken Getz and Robert Green | September 12, 2013

LINQ allows you to query over any type of generic list. The most common list type you'll use is List, but LINQ allows you to work with any of the following list types, in the System.Collections.Generic namespace unless otherwise specified:

  • List<T>
  • LinkedList<T>
  • Queue<T>
  • Stack<T>
  • HashSet<T>
  • System.Collections.ObjectModel.Collection<T>
  • System.ComponentModel.BindingList<T>

Just to prove the point, the sample project includes the QueryGenericList method. This method performs similar work to the earlier QueryArray method, this time showing both query syntax, and functional syntax. Listing 2 shows the entire procedure.

private static void QueryGenericList() { // Fill a generic list with FileInfo objects: var files = new List<FileInfo>(); files.AddRange( new DirectoryInfo(searchPath).GetFiles()); // Create the query this way: var query = from fi in files where fi.Length < 1000 orderby fi.Length descending, fi.Name select new { fi.Name, fi.Length };

 // Or you can create the query this way: query = files .Where(fi => fi.Length < 1000) .OrderByDescending(fi => fi.Length) .ThenBy(fi => fi.Name) .Select(fi => new { fi.Name, fi.Length }); DisplayResults("Generic lists:", query); }

Listing 2. The QueryGenericList method shows off several different techniques, including query vs. functional syntax. Running this procedure displays the output shown in the Figure below.

Generic lists: ============== { Name = WindowsShell.Manifest, Length = 749 } { Name = TMFilter.log, Length = 511 } { Name = system.ini, Length = 219 } { Name = win.ini, Length = 219 } { Name = ildasmfnt.bin, Length = 212 } { Name = QUICKEN.INI, Length = 192 } { Name = hpgmdl22.dat, Length = 173 } { Name = hpgmdl22.dat.temp, Length = 173 } { Name = SETUPAPI.LOG, Length = 94 } { Name = Addrfixr.ini, Length = 62 } { Name = S3A4ED6B1.tmp, Length = 48 } { Name = iltwain.ini, Length = 36 } { Name = bthservsdp.dat, Length = 12 } { Name = nsreg.dat, Length = 0 } { Name = setuperr.log, Length = 0 }

The Figure above. The QueryGenericList procedure provides a list of files. The QueryGenericList procedure starts by retrieving the array of files, and copying the data into a generic list:

var files = new List<FileInfo>(); files.AddRange( new DirectoryInfo(searchPath).GetFiles());

Next, the code uses standard query syntax to retrieve from the list all the files whose length is less than 1000 bytes, ordered first by length in descending order, and then for files with matching lengths, by file name. The query retrieves an anonymous type containing the Name and Length properties of the file:

var query = from fi in files where fi.Length < 1000 orderby fi.Length descending, fi.Name select new { fi.Name, fi.Length };

Finally, the procedure demonstrates the equivalent query, created using function syntax instead. This query returns the same data in the same order, but does it by calling extension methods with lambda expressions defining their behavior:

query = files .Where(fi => fi.Length < 1000) .OrderByDescending(fi => fi.Length) .ThenBy(fi => fi.Name) .Select(fi => new { fi.Name, fi.Length });

Note a few things about this query definition:

The Where function accepts a lambda expression that returns true or false for each item in the collection. Items for which the lambda expression returns false are excluded from the collection:

The OrderByDescending method (and its "cousin," the OrderBy method) accepts a lambda expression that returns information indicating how to sort the data. In this case, the sorting occurs based on the Length property of each FileInfo object:

Using the standard query syntax, you can indicate ordering by multiple columns by simply including the columns separated with a comma. In function syntax, you must use the ThenBy or ThenByDescending method to indicate a secondary sort. As a parameter to the method, pass a lambda expression which, again, indicates the sort order. In this case, the secondary sort uses the Name property of the input FileInfo object:

  • The Select method accepts a lambda expression that identifies which field or fields you want the query to return. In this case, the query returns an anonymous type containing the Name and Length properties 
fi => new { fi.Name, fi.Length }

NOTE Remember, all the techniques you've seen in this example apply to any type of LINQ query, not just LINQ to Objects, and not just queries that work with generic lists.

TIP: The System.Linq.Enumerable class provides a large number of extension methods that add behavior to queryable objects, much like the Select, Where, OrderBy, ThenBy, OfType, and other methods you've already seen. Later sections in this chapter introduce many of these methods. For more information, review the Microsoft documentation for the System.Linq.Enumerable class and its many methods.

  ldn-expertkgetzThis post is an excerpt from the online courseware for our Microsoft LINQ Using Visual C# 2010 course written by expert Ken Getz.



Ken Getz

Ken Getz is a featured instructor for several of our Visual Studio courses. He is a Visual Basic and Visual C# expert and has been recognized multiple times as a Microsoft MVP. Ken is a seasoned instructor, successful consultant, and the author or co-author of several best-selling books. He is a frequent speaker at technical conferences like Tech-Ed, VSLive, and DevConnections and he has written for several of the industry's most-respected publications including Visual Studio Magazine, CoDe Magazine, and MSDN Magazine.

Robert Green

Robert Green is a Visual Studio expert and a featured instructor for several of our Visual Basic and Visual C# courses. He is currently a Technical Evangelist in the Developer Platform and Evangelism (DPE) group at Microsoft. He has also worked for Microsoft on the Developer Tools marketing team and as Community Lead on the Visual Basic team. Robert has several years of consulting experience focused on developer training and is a frequent speaker at technology conferences including TechEd, VSLive, VSConnections, and Advisor Live.


This course excerpt was originally posted September 12, 2013 from the online courseware LINQ Using Visual C# 2010 by Ken Getz and Robert Green