I was watching a presentation today and noticed an implementation of GetHashCode() that was... less than perfect :)
For those without the luxury of Resharper, I thought I'd create a few examples of implementing the equality members. For a refresher on defining equality, see this MSDN article. Note that, while technically optional, it is recommended to overload the == and != operators too.
public class IntPrimaryKey : IEquatable<IntPrimaryKey>
{
public int PrimaryKey { get; set; }
public bool Equals(IntPrimaryKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return PrimaryKey == other.PrimaryKey;
}
public override bool Equals(object obj)
{
return Equals(obj as IntPrimaryKey);
}
public override int GetHashCode()
{
return PrimaryKey;
}
}
public class StringPrimaryKey : IEquatable<StringPrimaryKey>
{
public string PrimaryKey { get; set; }
public bool Equals(StringPrimaryKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(PrimaryKey, other.PrimaryKey);
}
public override bool Equals(object obj)
{
return Equals(obj as StringPrimaryKey);
}
public override int GetHashCode()
{
return PrimaryKey == null ? 0 : PrimaryKey.GetHashCode();
}
}
public class MultiNumberPrimaryKey : IEquatable<MultiNumberPrimaryKey>
{
public int PrimaryKey1 { get; set; }
public int PrimaryKey2 { get; set; }
public bool Equals(MultiNumberPrimaryKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return PrimaryKey1 == other.PrimaryKey1 && PrimaryKey2 == other.PrimaryKey2;
}
public override bool Equals(object obj)
{
return Equals(obj as MultiNumberPrimaryKey);
}
public override int GetHashCode()
{
unchecked
{
return (PrimaryKey1 * 397) ^ PrimaryKey2;
}
}
}
public class MultiStringPrimaryKey : IEquatable<MultiStringPrimaryKey>
{
public string PrimaryKey1 { get; set; }
public string PrimaryKey2 { get; set; }
public bool Equals(MultiStringPrimaryKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(PrimaryKey1, other.PrimaryKey1) && Equals(PrimaryKey2, other.PrimaryKey2);
}
public override bool Equals(object obj)
{
return Equals(obj as MultiStringPrimaryKey);
}
public override int GetHashCode()
{
unchecked
{
return ((PrimaryKey1 == null ? 0 : PrimaryKey1.GetHashCode()) * 397) ^ (PrimaryKey2 == null ? 0 : PrimaryKey2.GetHashCode());
}
}
}
public class MultiMixedPrimaryKey : IEquatable<MultiMixedPrimaryKey>
{
public int PrimaryKey1 { get; set; }
public string PrimaryKey2 { get; set; }
public bool Equals(MultiMixedPrimaryKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return PrimaryKey1 == other.PrimaryKey1 && Equals(PrimaryKey2, other.PrimaryKey2);
}
public override bool Equals(object obj)
{
return Equals(obj as MultiMixedPrimaryKey);
}
public override int GetHashCode()
{
unchecked
{
return (PrimaryKey1 * 397) ^ (PrimaryKey2 == null ? 0 : PrimaryKey2.GetHashCode());
}
}
}
public class MultiPrimaryKey : IEquatable<MultiPrimaryKey>
{
public int PrimaryKey1 { get; set; }
public int PrimaryKey2 { get; set; }
public int PrimaryKey3 { get; set; }
public int PrimaryKey4 { get; set; }
public bool Equals(MultiPrimaryKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return PrimaryKey1 == other.PrimaryKey1 && PrimaryKey2 == other.PrimaryKey2 && PrimaryKey3 == other.PrimaryKey3 && PrimaryKey4 == other.PrimaryKey4;
}
public override bool Equals(object obj)
{
return Equals(obj as MultiPrimaryKey);
}
public override int GetHashCode()
{
unchecked
{
int result = PrimaryKey1;
result = (result * 397) ^ PrimaryKey2;
result = (result * 397) ^ PrimaryKey3;
result = (result * 397) ^ PrimaryKey4;
return result;
}
}
}
public class MultiPrimaryKey2 : IEquatable<MultiPrimaryKey2>
{
public string PrimaryKey1 { get; set; }
public string PrimaryKey2 { get; set; }
public string PrimaryKey3 { get; set; }
public string PrimaryKey4 { get; set; }
public bool Equals(MultiPrimaryKey2 other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(PrimaryKey1, other.PrimaryKey1) && Equals(PrimaryKey2, other.PrimaryKey2) && Equals(PrimaryKey3, other.PrimaryKey3) && Equals(PrimaryKey4, other.PrimaryKey4);
}
public override bool Equals(object obj)
{
return Equals(obj as MultiPrimaryKey2);
}
public override int GetHashCode()
{
unchecked
{
int result = PrimaryKey1 == null ? 0 : PrimaryKey1.GetHashCode();
result = (result * 397) ^ (PrimaryKey2 == null ? 0 : PrimaryKey2.GetHashCode());
result = (result * 397) ^ (PrimaryKey3 == null ? 0 : PrimaryKey3.GetHashCode());
result = (result * 397) ^ (PrimaryKey4 == null ? 0 : PrimaryKey4.GetHashCode());
return result;
}
}
}
Tags: .net, bestpractices
I was poking around in my data the other day doing a bit of housekeeping and ran across the recoding of Paul Clements' final presentation to devloop before leaving the company. I hated to see it hidden away on my HDD so I decided to chop it up and post it for all to enjoy!
Wise words from a wise man: Paul's Final Iteration
Enjoy!
Tags: work, devloop, architecture, bestpractices