Aug 132009
 

The class at the end of this post contains some extension methods that I commonly use in my code:

  • IDictionary<TKey, TValue>.GetValueOrDefault
  • IEnumerable<T>.ToHashSet
  • IEnumerable<T>.ToJoinedString

GetValueOrDefault

GetValueOrDefault is a simple extension method that wraps the IDictionary.TryGetValue method. Since the TryGetValue method cannot be used in lambda expressions, it makes it difficult to use dictionary lookups in LINQ, for example. The GetValueOrDefault method offers a wrapper which silently tries to get a value based on a key. If the value does not exist in the dictionary, it will return either the default value for the value type or a supplied default value.

ToHashSet

There are several extension methods in LINQ which allow conversion from an IEnumerable to another collection type (ToList, ToArray, ToDictionary etc.). Sometimes it is useful to convert an IEnumerable to a HashSet, in order to perform quick lookups for a certain value.

The nice thing about the HashSet is that it has an O(1) lookup and insertion complexity, so it is really fast.

The ToHashSet extension method converts a source IEnumerable to a strongly typed HashSet, and has the possibility of supplying an IEqualityComparer. This is nice if the comparison logic is more complex or if you want for example to build a case-insensitive HashSet<string>.

ToJoinedString

One of the methods that is very common when working with string arrays is string.Join. Unfortunately, this method can only use string arrays. Of course you can always convert a string collection to an array and then apply the ToString method, but this induces some overhead, especially when the collection is large.

The ToJoinedString extension method does the same thing as string.Join but works on any type of IEnumerable. Internally it uses a StringBuilder object to concatenate strings, so it offers a high performance, even when working with large string collections.

The Code

Here is the code for the extension methods. You can just copy & paste the following code in your project and use it as is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public static class GenericCollectionExtensionMethods
{
    #region Methods

    /// <summary>
    /// Tries to get a value from a dictionary based on a supplied key. If the value does not exist in
    /// the dictionary it will return the default value for the value type.
    /// </summary>
    /// <typeparam name="TKey">The type of the key.</typeparam>
    /// <typeparam name="TValue">The type of the value.</typeparam>
    /// <param name="dict">The dictionary.</param>
    /// <param name="key">The key.</param>
    /// <returns>
    /// The value that corresponds to the supplied key or the default value for the value type.
    /// </returns>
    public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key)
    {
        TValue value;
        if (dict.TryGetValue(key, out value))
        {
            return value;
        }
        else
        {
            return default(TValue);
        }
    }

    /// <summary>
    /// Tries to get a value from a dictionary based on a supplied key. If the value does not exist in
    /// the dictionary it will return the supplied value.
    /// </summary>
    /// <typeparam name="TKey">The type of the key.</typeparam>
    /// <typeparam name="TValue">The type of the value.</typeparam>
    /// <param name="dict">The dictionary.</param>
    /// <param name="key">The key.</param>
    /// <param name="defaultValue">The default value.</param>
    /// <returns>
    /// The value that corresponds to the supplied key or the value of the 
    /// <paramref name="defaultValue"/> parameter.
    /// </returns>
    public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue defaultValue)
    {
        TValue value;
        if (dict.TryGetValue(key, out value))
        {
            return value;
        }
        else
        {
            return default(TValue);
        }
    }

    /// <summary>
    /// Converts the source to a hash set.
    /// </summary>
    /// <typeparam name="TSource">The type of the source.</typeparam>
    /// <param name="source">The source enumerable.</param>
    /// <returns>A typed hash set containing the items from the source enumerable.</returns>
    public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source)
    {
        return new HashSet<TSource>(source);
    }

    /// <summary>
    /// Converts the source to a hash set.
    /// </summary>
    /// <typeparam name="TSource">The type of the source.</typeparam>
    /// <param name="source">The source enumerable.</param>
    /// <param name="comparer">
    /// The comparer used by the hash set. This is useful for example when building a case insensitive
    /// hash set.
    /// </param>
    /// <returns>A typed hash set containing the items from the source enumerable.</returns>
    public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
    {
        return new HashSet<TSource>(source, comparer);
    }

    /// <summary>
    /// Joins the string representation of all items in an IEnumerable to a string, using a separator.
    /// </summary>
    /// <typeparam name="T">The type of the elements contained in source collection.</typeparam>
    /// <param name="source">The source collection</param>
    /// <param name="separator">The separator used to glue items together</param>
    /// <returns>
    /// A string obtained by glueing the collection items with the separator, similar to string.Join
    /// </returns>
    public static string ToJoinedString<T>(this IEnumerable<T> source, string separator)
    {
        var sb = new StringBuilder();
        bool first = true;
        foreach (var item in source)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                sb.Append(separator);
            }

            sb.Append(item.ToString());
        }

        return sb.ToString();
    }

    #endregion Methods
}