Home > .NET 3.5, C# 3.0, Lambda Expressions, LINQ > A Good, practical LINQ example

A Good, practical LINQ example

January 17, 2008

You may recall that one of my New Year’s Resolutions was to find and participate in a .NET Forum. Well, I have joined several, and have even posted a few times. While perusing the C# Corner forums today, I found this post about not being able to break out of a loop. The code was using one of my favorite techniques for Windows Forms, the ErrorProvider. I like ErrorProvider and use it quite a bit, and I have done what the poster was trying to do many times: loop through the Controls on a Form and find out whether any of them have an active error message. If they do, then I use that information to warn the user or set some Form state so that it is apparent that an error exists.

My answer does not specifically address the issue the poster brought to the table, but the post got me to thinking: we should be able to use LINQ to solve this problem. Here is a typical example of the loop construct:

bool hasErrors = false;
foreach (Control c in this.Controls)
    if (!"".Equals(errorProvider1.GetError(c)))
        hasErrors = true;

In looking at this, it appears we have a good case for using LINQ: we have a Collection and we want to query that Collection for information about itself. Seems it should be pretty straightforward, and ultimately it is, but in this particular case it took a little trial and error to hack it out. Since it wasn’t as simple as I originally thought it would be, let’s walk through it in stages.

Build a Queryable Object

The first step is to try and build a LINQ query of all the Controls on the Form:

var q = from c in this.Controls
        select c;

When I tried to compile this, I got an error I did not expect:

Could not find an implementation of the query pattern for source type ‘System.Windows.Forms.Control.ControlCollection’. ‘Select’ not found. Consider explicitly specifying the type of the range variable ‘c’.

Naturally, I reexamined the code and couldn’t find anything odd about it, but what did seem odd was that I knew this.Controls was a Collection, and LINQ is supposed to work on Collections, right? Wrong!

Getting a Sequence from a Collection

If you read my recent LINQ to Objects post you may recall that LINQ does not work on Collections, but rather Sequences. It soon dawned on me that ControlCollection does not qualify as a Sequence because it does not implement IEnumerable<T>, but rather IEnumerable. This led me to uncharted territory: how do I get an IEnumerable<T> from an IEnumerable? Well, there was definitely some trial and error, and a lot of IntelliSense browsing, but I finally figured out an elegant solution.

Microsoft was gracious enough to provide an IEnumerable extension method (my favorite new feature) that will cast an IEnumerable to an IEnumerable<T>. Fittingly, this method is named Cast<T>(). Here is the code that will transform our ControlCollection into a usable Sequence:

var q = from c in this.Controls.Cast<Control>()
        select c;

Now we have a LINQ query object representing all the Controls on our Form.

Querying the Queryable Object

Now that we have a Sequence instead of a Collection to work with, this could come in quite handy. In fact, this would be a good candidate for a ControlCollection Extension Method in its own right. In the meantime, now that we have a queryable object, we have several options for how to complete our task. One way is to query the entire Sequence when we need it. I’m going to use our friend the Lambda Expression to find out if there are any Controls with Errors in the errorProvider:

// Query as needed
MessageBox.Show(q.Count(c => !"".Equals(errorProvider1.GetError(c))) > 0 ? "There are errors!" : "No errors!");

Again we are using a supplied Extension Method called Count<>() and passing it a Func<> defined by our Lambda Expression. If the count is greater than 0, then we have errors, else we do not.

This approach is especially handy if you may need to query the list in multiple ways. In our case, however, we know that this criteria is the only one we will need, so we have the option to embed our Lambda in the LINQ statement itself. To do so, we will use yet another Extension Method called Where:

var q = from c in this.Controls.Cast<Control>()
        .Where(c => !"".Equals(errorProvider1.GetError(c)))
        select c;

You’ll notice that this is the same logic just implemented as part of the LINQ statement. Now our consuming code is a bit simpler because our list is defined as only the items with messages in the ErrorProvider:

// Now we don't need the Lambda
MessageBox.Show(q.Count() > 0 ? "There are errors!" : "No errors!");

Here is the complete code block:

var q = from c in this.Controls.Cast<Control>()
        .Where(c => !"".Equals(errorProvider1.GetError(c)))
        select c;
MessageBox.Show(q.Count() > 0 ? "There are errors!" : "No errors!");

Hopefully, as you experiment with these new features, you will come to appreciate how they all complement each other. This example turns out to be fairly simple, even though it took a little effort to work through. In it, we have taken advantage of Extension Methods, LINQ, and Lambda Expressions because they all work together. While these are all great additions on their own, the cumulative power they represent is outstanding. I guess .NET really is worth more than the sum of its parts.

  1. Ben
    June 16, 2008 at 8:05 pm


    How can I do it in vb.net. It seems that there is no equivalent casting like c#. I tried with CType and DirectCast with no success.

    Thanks a lot,


  2. June 17, 2008 at 8:27 am

    Hmmm… isn’t the Controls.Cast method available in VB.Net? It would seem to me that this should be .Net and not language specific.

  3. Ben
    June 17, 2008 at 8:54 am

    I tried differents fashions and I have always an error “expression expected” after the controls.Cast. It’s the reason why I suspect Vb.Net to support the casting differently.

  4. Matthew
    June 19, 2008 at 10:41 am

    Dim query = from c As Control in Me.Controls

    might just do the trick

  5. Chato
    July 24, 2008 at 12:43 pm

    Hey Ben I think linqhelp.com has a solution to your Control.cast problem. Try searching over there. Nice read btw!

  6. Greg
    July 30, 2008 at 4:14 pm

    Actually, Ben’s query can use the typical LINQ query using type inference for the range variable and it will work just fine. For example:

    Dim query = _
    From c in Controls _
    Where TypeOf c Is TextBox _
    Select c

    will select all the TextBoxes in the Controls collection. For some reason, VB does not place the same restriction on querying the Controls collection as C# does.

  7. June 16, 2009 at 10:38 pm
  8. January 28, 2010 at 4:01 am

    Thank You for Helpful

  9. April 6, 2010 at 8:04 pm

    “foreach” is doomed.

  10. Fab
    May 19, 2010 at 6:52 am

    I thinks the following works too:

    var q = from Control c in this.Controls
    select c;

  11. Eklavya Gupta
    July 7, 2010 at 2:05 am

    Cool! Thanks for the post. Was very useful.

  12. December 11, 2010 at 11:47 am

    Good work. Keep it up. Well explained.

  13. Dharmesh Barochia
    January 10, 2011 at 3:54 am

    I found one more reference site for LINQ and LAMBDA example.


  1. January 20, 2008 at 9:42 pm
Comments are closed.
%d bloggers like this: