Over a month ago I did a presentation on LINQ and promised a few people I’d share the code from the session. Better late than never, eh?
We warmed up by building our own filtering operator to use in a query. The operator takes an Expression<Predicate<T>>, which we need to compile before we invoking the predicate inside.
public static class MyExtensions { public static IEnumerable<T> Where<T>( this IEnumerable<T> sequence, Expression<Predicate<T>> filter) { foreach (T item in sequence) { if (filter.Compile()(item)) { yield return item; } } } }
The following query uses our custom Where operator:
IEnumerable<Employee> employees = new List<Employee>() { new Employee() { ID= 1, Name="Scott" }, new Employee() { ID =2, Name="Paul" } }; Employee scott = employees.Where(e => e.Name == "Scott").First();
Of course, if we are just going to compile and invoke the expression there is little advantage to using an Expression<T>, but it generally turns into an “a-ha!” moment when you show someone the difference between an Expression<Predicate<T>> and a plain Predicate<T>. Try it yourself in a debugger.
We also wrote a LINQ version of “Hello, World!” that reads text files from a temp directory (a.txt would contain “Hello,”, while b.txt would contain “World!”. A good demonstration of map-filter-reduce with C# 3.0.
var message = Directory.GetFiles(@"c:\temp\") .Where(fname => fname.EndsWith(".txt")) .Select(fname => File.ReadAllText(fname)) .Aggregate( new StringBuilder(), (sb, s) => sb.Append(s).Append(" "), sb => sb.ToString() ); Console.WriteLine(message);
Moving into NDepend territory, we also wrote a query to find the namespaces with the most types (for referenced assemblies only):
var groups = Assembly.GetExecutingAssembly() .GetReferencedAssemblies() .Select(aname => Assembly.Load(aname)) .SelectMany(asm => asm.GetExportedTypes()) .GroupBy(t => t.Namespace) .OrderByDescending(g => g.Count()) .Take(10); foreach (var group in groups) { Console.WriteLine("{0} {1}", group.Key, group.Count()); foreach (var type in group) { Console.WriteLine("\t" + type.Name); } }
And finally, some LINQ to XML code that creates an XML document out of all the executing processes on the machine:
XNamespace ns = "http://odetocode.com/schemas/linqdemo"; XNamespace ext = "http://odetocode.com/schemas/extensions"; XDocument doc = new XDocument( new XElement(ns + "Processes", new XAttribute(XNamespace.Xmlns + "ext", ext), from p in Process.GetProcesses() select new XElement(ns + "Process", new XAttribute("Name", p.ProcessName), new XAttribute(ext + "PID", p.Id))));
Followed by a query for the processes ID of any mspaint instances:
var query = (from e in doc.Descendants(ns + "Process") where (string)e.Attribute("Name") == "mspaint" select (string)e.Attribute(ext + "PID"));
More on LINQ to come…
Comments
Is there other consideration?
foreach (T item in sequence)
{
if (filter.Compile()(item))
Actually be:
Predicte pred = filter.Compile();
foreach (T item in sequence)
{
if (pred(item))
There's no really sense in recompiling it every time...
Good point - I did show both techniques.
The one advantage to casting is when dealing with optional attributes. Casting will yield a null string reference while .Value will throw an exception.
I was doing some work with reflection today and started off by looping through a load of PropertyInfos. Then I remembered this blog post and trimmed it all down to one line.
Great post Scott, thanks very much.