Having fun with "Group-Ease"

Posted Sun, Jul 8 2007 5:06 by bill

(note the title is phonetic <g>)

I thought I'd write a simple Group By query to list the controls on a form grouped by their type. 

 

Dim query = From c In Me.Controls Group c By c.GetType.Name Into Members

 

Then to write out the code I wrote:

For Each group In query
    Debug.Print("----- Control Type =" & group.Name & "-------")
    For Each cntl As Control In group.Members
        Debug.Print(cntl.Name)
    Next
Next

That'll list the controls grouped by their type. Pretty simple, but we can improve the query a bit.

 

(1)  First improvement is to make it more strongly typed. The Me.Controls returns a ControlsCollection which was designed before generics, so it's IEnumerable is As Object.  This isn't obvious in the above query , and you avoid the issue of casting when you iterate by specifying For each cntl As Control In ....  Currently you can't specify the cast to be made on the c variable in the From clause, but you can effectively cast the Controls collection via the Cast(Of TResult) extension.  The query hence becomes :

 

Dim query = From c In Me.Controls.Cast(Of Control)() Group c By c.GetType.Name Into Members

 

Now the query is strongly typed through-out.

 

 

(2) the next thing you might want to do is sort the grouping.  There's two levels of sorting you can do, one is inside the group, and the other is sorting the group itself.  To sort the groups, we add a Order By Name to the end of the query.

 

Dim query = From c In Me.Controls.Cast(Of Control)() Group c By c.GetType.Name Into Members Order By Name

 

The "Name" variable is created from the c.GetType.Name part of the Group By clause, so you are really sorting by the calculated value of c.GetType.Name.  You could give the grouping criteria a different name if you wanted, such as TypeName might be appropriate here :

 

Dim query = From c In Me.Controls.Cast(Of Control)() Group c By TypeName = c.GetType.Name Into Members Order By TypeName

 

If you want to also sort the controls inside each group, you can add an Order By clause before the grouping:

 

Dim query = From c In Me.Controls.Cast(Of Control)() Order By c.Name Group c By TypeName = c.GetType.Name Into Members Order By TypeName

 

(3) Now you probably want to make your code a little more readable and break that whopping one liner into a neater block :

 

Dim query = From c In Me.Controls.Cast(Of Control)() _
                    Order By c.Name _
                    Group c By TypeName = c.GetType.Name Into Members _
                    Order By TypeName

 

(4) Finally, you can make the query a little bit more explicit by including the Select clause.  As it stands the query is implicitly selecting the TypeName and Members, hence the query is returning an IEnumerable(Of String, IEnumerable(Of Control)).  That may not be obvious to people looking at the code, so adding the Select clause helps a bit in spelling that out.

Dim query = From c In Me.Controls.Cast(Of Control)() _
                    Order By c.Name _
                    Group c By TypeName = c.GetType.Name Into Members _
                    Order By TypeName  _
                    Select TypeName, Members

 

 Note: the Select clause is optional in this case.  If you find it adds readability add it

Filed under: , ,

Comments

# What's new in June Orcas CTP for VB

Sunday, July 08, 2007 10:25 PM by @ Head

Many of the little features are in VB Orcas as of June (no need to wait till Beta 2) (1) Lambda functions