When performing code review, I am occasionally surprised to find something in the .Net Framework that I never knew existed. Today when I was reviewing code from a developer on a sister project, I found HashSet<T>. HashSet<T> class, introduced to the .Net Framework in version 3.5 provides developers with some high performance set operations. In the past, I have used the Set<T> from the PowerCollection library but I have not used the new HashSet<T>.
In the code I was reviewing, a developer was using HashSet to find the intersection of two -- requesters and approvers. Obviously, a requester cannot be an approver so finding the people that are in both groups (Intersection) will enable you to remove them from the request. Here is an example of how the developer was using the new HashSet object.
Example of a HashSet
The solution is a reasonable use of the HashSet functionality but it is a little verbose due to the creation of the HashSets even though we already had the generic lists of requesters and approvers. Upon further investigation of the HashSet on MSDN, I found that LINQ to objects has a subset of HashSet features that include Union, Intersect, Except and Distinct operations.
HashSet Operations
| HashSet |
LINQ |
Explination |
| UnionWith |
Union |
Produces the set union of two sequences. |
| IntersectWith |
Intersect |
Produces the set intersection of two sequences. |
| ExceptWith |
Except |
Produces the set difference of two sequences. |
| Not Provided |
Distinct |
Returns distinct elements from a sequence. |
| SymmetricExceptWith |
Not Provided. |
Modifies the current HashSet<T> object to contain only elements that are present either in that object or in the specified collection, but not both. |
| Overlaps |
Not Provided. |
Determines whether the current HashSet<T> object overlaps the specified collection. |
| IsSubsetOf |
Not Provided. |
Determines whether a HashSet<<T> object is a subset of the specified collection. |
| IsProperSubsetOf |
Not Provided. |
Determines whether a HashSet<T> object is a proper subset of the specified collection. |
| IsSupersetOf |
Not Provided. |
Determines whether a HashSet<T> object is a superset of the specified collection. |
| IsProperSupersetOf |
Not Provided. |
Determines whether a HashSet<T> object is a proper superset of the specified collection. |
| SetEquals |
Not Provided. |
Determines whether a HashSet<T> object and the specified collection contain the same elements. |
Example of LINQ Intersect
Using the IEnumerable Intersect extension method we can clean up the code with a little LINQ to objects goodness.
The LINQ to object version is considerably shorter and has a much lower maintenance complexity score. I also like the fact that I was able to keep the person objects in the intersection and not have to convert them to a list of ID, like in the original code. This is a simple example with simple types but does show how knowing what's available in the Framework can make your code more readable by you, and more importantly, by a maintenance developer.
The Enumerable type has two intersect methods. The first one just takes a IEnumerable<TSource> and uses the TSource's Equals and GetHashCode functions for equality checking. The second intersect method takes an IEnumerable<TSource> and a IEqualityComparer<TSource> and uses the equality comparer object for comparisons.
Conclusions
Code reviews can be a painful experience for both the developer and the reviewer but with the right attitude and a supportive environment, they can be a great way to expand your development knowledge. Reviewing good code from the major open source projects is something I do often and would encourage you to do the same.
Links