Recently I needed to use some kind of range representation, which could also work as a dictionary key. For this purpose, the object (derived from IEquatable at the very least), has to implement the Equals method and the GetHashCode method. My range implementation is inspired by the Tuple from the .NET framework. Here’s the code:
public class Range : IStructuralEquatable, IStructuralComparable, IComparable {
public int Start { get; set; }
public int End { get; private set; }
public int Size {
get { return End - Start; }
}
public Range(int start, int end) {
if (Start > End) throw new ArgumentException("Start cannot be greater than End.");
Start = start;
End = end;
}
public int CompareTo(object obj) {
return ((IComparable)this).CompareTo(obj);
}
public int CompareTo(object other, IComparer comparer) {
return ((IStructuralComparable)this).CompareTo(other, comparer);
}
public override bool Equals(object obj) {
return ((IStructuralEquatable)this).Equals(obj, EqualityComparer<object>.Default);
}
public bool Equals(object other, IEqualityComparer comparer) {
if (other == null) return false;
var otherRange = other as SlidingWindowRange;
if (otherRange == null) return false;
return comparer.Equals(Start, otherRange.Start) && comparer.Equals(End, otherRange.End);
}
int IComparable.CompareTo(Object obj) {
return ((IStructuralComparable)this).CompareTo(obj, Comparer<object>.Default);
}
int IStructuralComparable.CompareTo(Object other, IComparer comparer) {
if (other == null) return 1;
var otherRange = other as SlidingWindowRange;
if (otherRange == null) {
throw new ArgumentException("Incorrect type of other object.");
}
int c = comparer.Compare(Start, otherRange.Start);
return c == 0 ? comparer.Compare(End, otherRange.End) : c;
}
public override int GetHashCode() {
return ((IStructuralEquatable)this).GetHashCode(EqualityComparer<object>.Default);
}
int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
return Range.CombineHashCodes(comparer.GetHashCode(Start), comparer.GetHashCode(End));
}
public int GetHashCode(IEqualityComparer comparer) {
return ((IStructuralEquatable)this).GetHashCode(comparer);
}
internal static int CombineHashCodes(int h1, int h2) {
return (((h1 << 5) + h1) ^ h2);
}
public override string ToString() {
StringBuilder sb = new StringBuilder();
return (this).ToString(sb);
}
string ToString(StringBuilder sb) {
sb.Append("(");
sb.Append(Start);
sb.Append(" - ");
sb.Append(End);
sb.Append(")");
return sb.ToString();
}
}
