C# Utility Class: CompundKey

C# No Comments »

While working in C#, I’ve often found that I want to use more than one variable as a key to a Hashtable. I’ve abstracted this functionality into an object called CompundKey. CompoundKey allows one to combine any number of variables into a single object which, through proper implementation of Equals(), GetHashCode(), and ToString(), can be used as a key to any IDictionary or even System.Web.Caching.Cache.

Usage is very simple. For example:

IDictionary urlUserAccessTimes = new Hashtable();
CompoundKey urlUserKey = new CompoundKey(new Uri("http://www.deez.info/sengelha/", "Steven Engelhardt"));
urlUserAccessTimes[urlUserKey] = DateTime.Now;

Here’s the code:

CompoundKey code
/// <summary>
/// Creates a key for an IDictionary or a System.Web.Caching.Cache
/// out of a collection of values.
/// </summary>
/// <remarks>
/// Each value stored in CompoundKey must implement Equals()
/// correctly.
/// </remarks>
public struct CompoundKey
{
    private object[] m_keyParts;

    public CompoundKey(params object[] keyParts)
    {
        Debug.Assert(keyParts != null);

        m_keyParts = keyParts;
    }

    public override bool Equals(object obj)
    {
        if (!(obj is CompoundKey))
            return false;

        CompoundKey key = (CompoundKey) obj;
        return ArrayUtils.Equals(m_keyParts, key.m_keyParts);
    }

    public override int GetHashCode()
    {
        int hashCode = 0;
        foreach (object keyPart in m_keyParts)
        {
            if (keyPart != null)
            {
                hashCode ^= keyPart.GetHashCode();
            }
        }
        return hashCode;
    }

    /// <remarks>
    /// Unfortunately, System.Web.Caching.Cache uses strings as keys
    /// instead of objects.
    /// </remarks>
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();

        foreach (object keyPart in m_keyParts)
        {
            if (sb.Length > 0)
                sb.Append(",");
            sb.Append(keyPart != null ? keyPart.ToString() : "(null)");
        }

        return sb.ToString();
    }
}

C# Utility Class: ArrayUtils

C# No Comments »

At work, I’ve written a collection of C# utility classes which implement commonly used functionality. The classes are encapsulated in a class library project which is included by virtually every C# application or class library I write. One of the simplest utility classes I’ve written is called ArrayUtils, and it is (duh) a set of useful functions for dealing with arrays. First, the code:

ArrayUtils code
/// <summary>
/// ArrayUtils is a collection of static helper functions which implement
/// common array tasks.
/// </summary>
public sealed class ArrayUtils
{
    /// <summary>
    /// Determines whether the provided array contains the specified
    /// member.
    /// </summary>
    /// <remarks>
    /// Execution time is O(n).
    /// </remarks>
    public static bool Contains(Array a1, object val)
    {
        Debug.Assert(a1 != null);
        Debug.Assert(val != null);

        foreach (object o in a1)
        {
            if (Object.Equals(o, val))
                return true;
        }

        return false;
    }

    /// <summary>
    /// Determines whether the provided array has any duplicated members.
    /// </summary>
    /// <remarks>
    /// Execution time is O(n^2).
    /// </remarks>
    public static bool ContainsDuplicates(Array a1)
    {
        Debug.Assert(a1 != null);

        for (int i = 0; i < a1.Length; i++)
        {
            for (int j = i + 1; j < a1.Length; j++)
            {
                if (Object.Equals(a1.GetValue(i), a1.GetValue(j)))
                {
                    return true;
                }
            }
        }

        return false;
    }

    /// <summary>
    /// Determine whether the two arrays are equal.  Equality is defined
    /// as having the same number of members and each member, in order,
    /// matches the corresponding member in the other array.
    /// </summary>
    /// <remarks>
    /// Execution time is O(n).
    /// </remarks>
    public static bool Equals(Array a1, Array a2)
    {
        Debug.Assert(a1 != null);
        Debug.Assert(a2 != null);

        if (a1.Length != a2.Length)
            return false;

        for (int i = 0; i < a1.Length; i++)
        {
            if (!Object.Equals(a1.GetValue(i), a2.GetValue(i)))
                return false;
        }

        return true;
    }

    private ArrayUtils() {}
}

Most of the code is very straight forward. Here’s a few pieces which I believe deserve closer attention:

public sealed class ArrayUtils
{
    ...

    private ArrayUtils() {}
}

The Utils suffix on the class name is a convention I use to denote a class with only static methods. The combination of sealed and a private constructor is a common idiom when declaring such classes. The next version of C#, Whidbey, introduces a static class attribute to denote such classes; classes with this attribute will be disallowed from declaring any non-static methods.

public static bool Contains(Array a1, object val)
{
    Debug.Assert(a1 != null);
    Debug.Assert(val != null);

    ...
}

I tend to use debug-only parameter validation for my utility classes; the alternative is to do things such as throw ArgumentNullExceptions. My justification is that these utility methods are internal and all validation should have been performed before calling them. I’m not particularly beholden to this convention—I consider there to be a decent chance that in the future I will change my mind.

if (Object.Equals(o, val))

I am very careful to use Object.Equals() throughout this class to allow for the possibility that either object may be null and to consider two null objects identical.

The rest, I think, is self-explanatory. Future posts about these C# utility classes should be more interesting as I plan to discuss much less trivial code.

By the way, I mentioned earlier that this post was going to be part of of a series. I’ve changed my mind; these utility classes are largely independent and will stand on their own.

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in