The New Generic Kid on the Block–HashSet<T>

0 comments

Posted on 25th January 2008 by r2 in Generics

In mathematics, a Set is typically thought of as a collection of distinct objects that is usually defined by some rule that determines whether they are a member of that particular Set.  For example, a Set could be defined to contain "all the odd numbers under 100" or "every number divisible by 2" or whatever.  The main points here being that the objects in a Set are distinct (i.e. NO duplicate objects are allowed) and the objects are not ordered or sorted in any way.  (If you really feel the need to geek out on Set Theory, be my guest).

According to the MSDN Documentation for HashSet, "a set is a collection that contains no duplicate elements, and whose elements are in no particular order."  Sound familiar?  In the .NET Base Class Library, there has never been a true Set class until now with the release of .NET 3.5 and the brand-spanking-new System.Collections.Generic.HashSet<T> class.

In the past, when we needed to implement a Set in .NET, we sort of bastardized the List<T> or other unsuspecting Collection classes into something like this:

  1. int[] intArray = new int[]{ 1, 2, 5, 7, 4, 1, 7, 9, 8};
  2. List<int> intList = new List<int>();
  3. foreach(int theInt in intArray)
  4. {
  5.   // checking to make sure that the object is not in our List before adding
  6.   //  so we are calling Contains() and then Add() on every time through the loop
  7.   if (!intList.Contains(theInt))
  8.     intList.Add(theInt);
  9. }

What we needed was a Set that would let us just keep adding objects to it and free us from having to worry about it being there first.  A recent example of when I really needed a true Set class was while working on the Weather WidgetThe Weather Channel provides some 40+ images for use in their SDK, yet in the Weather Widget I never need more than maximum of 11 (and usually less as there is usually duplication).  So, I had the idea to dynamically zip the images that I actually needed for a given Zip Code and use that file for my image assets in Silverlight via CreateXamlFromDownloader. Obviously, I don’t want these images duplicated in the zip file.  So, I came up with this:

  1. HashSet<string> assets = new HashSet<string>();
  2. foreach (ForecastDay day in forecast.Days)
  3. {
  4.   // no Exception here if duplicate…it just doesn't add it.
  5.   assets.Add(Server.MapPath(String.Format("~/images/{0}", day.IconDay)));
  6. }
  7. Utility.WriteZipFile(assets.ToArray<string>());

This just scratches the surface of what HashSet<T> is capable of.  There are member methods available for most Set operations, such as IntersectWith(), UnionWith(), IsSubsetOf(), IsSupersetOf(), RemoveWhere(), etc.   Here’s a link to all of the HashSet<T> Members.

Recall that being a member of a set depends on some rule that determines this membership.  With the HashSet<T>, you can define your own rule of what it means to be in a Set.  For a good example of defining your own EqualityComparer, see Introducing HashSet<T> from Kim Hamilton on the BCL Team Blog.

So, welcome the New Kid on the Block to the Generic Collections.

One last random link I had on the subject for those interested in LINQ:

Good side-by-side comparison of the HashSet and LINQ Set Operations

Time for T : An Introduction to .NET Generics

0 comments

Posted on 8th October 2007 by r2 in Generics |Presentations

Finally able to grab a minute to post my code and slides from the Introduction to Generics presentation that I did this past weekend at the Alabama Code Camp at the University of Alabama.

This is the abstract from the presentation:

With the release of the 2.0 version of the .NET Framework, Generics became first class citizens in the Common Language Runtime.  Yet, many still shy away from using them because of perceived difficulty or other misconceptions.   This presentation will seek to dispel a few of these myths and offer a gentle introduction into using Generics on a daily basis.  Along the way, I’ll also demonstrate language enhancements in the .NET 3.5 runtime that lend themselves nicely to working with Generics. 

Get the download here

Note:  The code is compiled on Visual Studio 2008 (Orcas) Beta 2.  The only project in the solution that uses .NET 3.5 specific code is the Collections project.  This uses C# 3.5 Automatic Properties and Property Initializers. 

Generic Methods: Find Controls by Type

0 comments

Posted on 8th October 2007 by r2 in Generics

Although this was originally part of my recent Generics presentation, I have received several requests to publish it separately.

The reason that I created this originally was that I found myself often-times wanting a strongly-typed list of all the checkboxes / buttons / etc in my code-behind/beside pages.  There is the Page.FindControl(string id), but that only allows you to get a control by id and it returns a Control.  I wanted something more specific, yet generic enough to use as a Utility.  This was screaming for Generic Methods, so below is what I came up with.

 

I use this constantly and hope that someone else gets some mileage out of it.  If you have improvements, please post them.  For example usage, download the full Generics presentation.

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows.Controls;
  4.  
  5. namespace r2musings.Web.UI.WebControls
  6. {
  7.     public static class Utility
  8.     {
  9.         #region FindControlsByType
  10.         /// <summary>
  11.         ///   Returns a generic list of controls of a provided type starting at a
  12.         ///    a provided base control (works recursively)
  13.         ///    Example Usage:  
  14.         ///       List<Button> buttonList = Utility.FindControlsByType<Button>(testPanel);
  15.         ///       This would return a list of all Buttons contained anywhere within testPanel
  16.         /// </summary>
  17.         /// <typeparam name="T">Type of control</typeparam>
  18.         /// <param name="parentControl">Base control to start search</param>
  19.         /// <returns></returns>
  20.         public static List<T> FindControlsByType<T>(Control parentControl)
  21.                     where T: System.Web.UI.Control
  22.         {
  23.             // new up our return list
  24.             List<T> returnList = new List<T>();
  25.  
  26.             // loop through all controls and call internal recursion to
  27.             //   add all controls of type T to the returnList
  28.             foreach (Control childControl in parentControl.Controls)
  29.             {
  30.                 InternalFindControlsByType<T>(childControl, returnList);
  31.             }
  32.  
  33.             // return our List<T>
  34.             return returnList;
  35.         }
  36.         
  37.         #endregion
  38.  
  39.         #region Recursion Method
  40.         
  41.         /// <summary>
  42.         ///   Should NOT call this method directly
  43.         ///   This is for the internal recursion of FindControlsByType()  
  44.         /// </summary>
  45.         /// <typeparam name="T">Type of control</typeparam>
  46.         /// <param name="parentControl">Base control to start search</param>
  47.         /// <param name="returnList">List to add Controls</param>
  48.         private static void InternalFindControlsByType<T>(
  49.             Control parentControl, List<T> returnList)
  50.             where T: System.Web.UI.Control
  51.         {
  52.             if (returnList == null)
  53.                 throw new ArgumentNullException("Null List passed to InternalFindControlsByType");
  54.  
  55.             if (parentControl is T)
  56.             {
  57.                 returnList.Add((T) parentControl);
  58.             }
  59.  
  60.             foreach (Control childControl in parentControl.Controls)
  61.             {
  62.                 // call this method recursively to get all child controls
  63.                 InternalFindControlsByType(childControl, returnList);
  64.             }
  65.         }
  66.  
  67.         #endregion
  68.     }
  69. }