views:

182

answers:

1

I have the following class which is part of a statictical analysis package.

  • The MetricKey object is used as a dictionary key.
  • Decision, MetricUnit & Portfolio are all enums.

I had to override the equality operator (==) to get dictionary key matching working. I used the guidance at http://msdn.microsoft.com/en-us/library/ms173147.aspx. The guidance said I should overload the GetHashCode method which I have done but I don't understand the implications of casting my enums to integers for the XOR (^) operation. Is what I've done valid or will I get conflicting hash codes due to my enum integer values overlapping?:

public class MetricKey
{
    public MetricKey(Decision decision, MetricUnit metricUnit, Portfolio portfolio)
    {
        Decision = decision;
        Unit = metricUnit;
        Portfolio = portfolio;
    }

    public Decision Decision { get; private set; }
    public MetricUnit Unit { get; private set; }
    public Portfolio Portfolio { get; private set; }

    public static bool operator == (MetricKey a, MetricKey b)
    {
        if (ReferenceEquals(a, b))
            return true;
        if (((object) a == null) || ((object) b == null))
            return false;
        return a.Decision == b.Decision && a.Unit == b.Unit && a.Portfolio == b.Portfolio;
    }

    public static bool operator != (MetricKey a, MetricKey b)
    {
        return !(a == b);
    }

    public override bool Equals(System.Object obj)
    {
        if (obj == null)
            return false;
        var metricKey = obj as MetricKey;
        if ((System.Object) metricKey == null)
            return false;
        return Decision == metricKey.Decision && Unit == metricKey.Unit && Portfolio == metricKey.Portfolio;
    }

    public bool Equals(MetricKey metricKey)
    {
        if ((object) metricKey == null)
            return false;
        return Decision == metricKey.Decision && Unit == metricKey.Unit && Portfolio == metricKey.Portfolio;
    }

    public override int GetHashCode()
    {
        return (int)Decision ^ (int)Unit ^ (int)Portfolio;
    }
}
+2  A: 

There is nothing wrong with the cast to int - however, I would actually avoid xor - it is easy to create collisions with likely values of the enums (1,2,3, etc). Note that collisions don't break anything, but they can make things more expensive. I might use something like (picking at random taking inspiration from the C# compiler's handling of anonymous types):

int num = -1962473570;
num = (-1521134295 * num) + (int)Decision;
num = (-1521134295 * num) + (int)Unit;
return (-1521134295 * num) + (int)Portfolio;
Marc Gravell
(note that if it was anything more complex than an enum you should call .GetHashCode() on it (checking for null first) - as it happens the GetHashCode() for an int is "return this", so not much point ;-p)
Marc Gravell