Tuesday, October 9, 2007

LINQ to Textbox


var lines = textbox1.Lines.Select( l => l.Contains( "the" ) );


The point of this post is that LINQ is everywhere. Use it on whatever you want. The above shows the "Select" that LINQ adds to collections, arrays, etc when you include the System.Linq namespace. Below is the more SQL-like query syntax, with an added condition and a trim. It returns all the lines that have "the" in it.


var lines = from line in textbox1.Lines
where line.Contains( "the" ) && line.Length > 10
select line.Trim();



I wrote a simple application that has two large text boxes and a small text box. The example program only has 1 statement, which is the following.


txtResult.Lines = (from line in txtToSearch.Lines
where line.Contains(txtSearchString.Text)
select line).ToArray();


I get bug reports in large text files (which include historical bug data, call stack, loaded modules, etc) automatically emailed to me from our application. I can paste the bug report into the txtToSearch control, type in "up time" into the single line txtSearchString control, and the results are put into the multi-line txtResult control and it will pull out all the lines that have either system or program up times. LINQ is great.

LINQ to Processes


var procs = ( from proc in Process.GetProcesses()
where proc.PriorityClass == ProcessPriorityClass.Normal &&
proc.StartTime < DateTime.Now.AddHours( -6 ) &&
proc.TotalProcessorTime.TotalMinutes > 30 &&
proc.Responding &&
!proc.MainModule.FileVersionInfo.IsDebug
select proc ).ToList();

This query pulls back a List of Process objects that are running with normal priority, have been running for more than 6 hours, have used more than 30 minutes of processor time, are still responding and are not debug builds.

If security settings prevent you from getting details on a process, this query will throw an exception.

LINQ to Files

In a very simple example, "files" is IEnumerable of string.


var files = from file in Directory.GetFiles(Environment.CurrentDirectory)
select file;


But that's boring and in no way uses the querying power of LINQ. So, let's spice it up.

var files = from file in Directory.GetFiles(Environment.CurrentDirectory, "tmp*.*")
where File.GetLastWriteTime(file) > DateTime.Now.AddDays(-2) &&
(File.GetAttributes(file) != FileAttributes.System)
orderby File.GetCreationTime(file)
select file;

This query finds non-system files modified within the past 2 days where the name starts with "tmp" where it's been ordered based on the creation date.

This next one works but what is wrong with it?


var files = from file in Directory.GetFiles(Environment.CurrentDirectory)
where new FileInfo(file).CreationTime > DateTime.Now.AddDays(2)
select file;


It's technically ok to new up objects in a LINQ query and sometimes is exactly what you want to do. In this case, it was to get the CreationTime from the FileInfo object. However, since there's the static File.GetCreationTime(f) function that returns a DateTime rather than the heavier FileInfo object, it reduces how much memory is used. Imagine doing this call repeatedly on large directories... it'd sure give the GC something to work on.

Let's say we want to have a query that peers into sub directories as well...


var files = from dir in Directory.GetDirectories( Environment.CurrentDirectory, "DLS*" )
from file in Directory.GetFiles( dir, "*.exe" )
where FileVersionInfo.GetVersionInfo( file ).CompanyName.Contains( "Microsoft" )
select file;


So, that query first gets all the directories that match a naming pattern of "DLS*", then in each one of those directories, it gets all of the exe's and only returns the ones where the CompanyName contains "Microsoft". Notice that there are two from statements (it's like nesting a for loop).

The function "GetDirectories" just returns an array of strings, which of course can be used in LINQ queries.

Then, you just do whatever you want to with the results:


foreach (string file in files)
{
File.Delete( file );
}

LINQ Stuff

There's so much hype around LINQ to SQL (DLINQ) and LINQ to XML (XLINQ) that some really cool uses have been totally ignored. This blog is to show examples of LINQ for completely other uses, querying over system and user collections.

Whenever I see that a function returns an array, generic list, or anything that supports IEnumerable then I figure out how I could use it in a LINQ query.