//******************************
// Written by Peter Golde
// Copyright (c) 2004-2005, Wintellect
//
// Use and restribution of this code is subject to the license agreement
// contained in the file "License.txt" accompanying this file.
//******************************
using System;
using System.Collections.Generic;
namespace Wintellect.PowerCollections
{
///
/// Stores a pair of objects within a single struct. This struct is useful to use as the
/// T of a collection, or as the TKey or TValue of a dictionary.
///
[Serializable]
public struct Pair : IComparable, IComparable>
{
///
/// Comparers for the first and second type that are used to compare
/// values.
///
private static IComparer firstComparer = Comparer.Default;
private static IComparer secondComparer = Comparer.Default;
private static IEqualityComparer firstEqualityComparer = EqualityComparer.Default;
private static IEqualityComparer secondEqualityComparer = EqualityComparer.Default;
///
/// The first element of the pair.
///
public TFirst First;
///
/// The second element of the pair.
///
public TSecond Second;
///
/// Creates a new pair with given first and second elements.
///
/// The first element of the pair.
/// The second element of the pair.
public Pair(TFirst first, TSecond second)
{
this.First = first;
this.Second = second;
}
///
/// Creates a new pair using elements from a KeyValuePair structure. The
/// First element gets the Key, and the Second elements gets the Value.
///
/// The KeyValuePair to initialize the Pair with .
public Pair(KeyValuePair keyAndValue)
{
this.First = keyAndValue.Key;
this.Second = keyAndValue.Value;
}
///
/// Determines if this pair is equal to another object. The pair is equal to another object
/// if that object is a Pair, both element types are the same, and the first and second elements
/// both compare equal using object.Equals.
///
/// Object to compare for equality.
/// True if the objects are equal. False if the objects are not equal.
public override bool Equals(object obj)
{
if (obj != null && obj is Pair) {
Pair other = (Pair)obj;
return Equals(other);
}
else {
return false;
}
}
///
/// Determines if this pair is equal to another pair. The pair is equal if the first and second elements
/// both compare equal using IComparable<T>.Equals or object.Equals.
///
/// Pair to compare with for equality.
/// True if the pairs are equal. False if the pairs are not equal.
public bool Equals(Pair other)
{
return firstEqualityComparer.Equals(First, other.First) && secondEqualityComparer.Equals(Second, other.Second);
}
///
/// Returns a hash code for the pair, suitable for use in a hash-table or other hashed collection.
/// Two pairs that compare equal (using Equals) will have the same hash code. The hash code for
/// the pair is derived by combining the hash codes for each of the two elements of the pair.
///
/// The hash code.
public override int GetHashCode()
{
// Build the hash code from the hash codes of First and Second.
int hashFirst = (First == null) ? 0x61E04917 : First.GetHashCode();
int hashSecond = (Second == null) ? 0x198ED6A3 : Second.GetHashCode();
return hashFirst ^ hashSecond;
}
///
/// Compares this pair to another pair of the some type. The pairs are compared by using
/// the IComparable<T> or IComparable interface on TFirst and TSecond. The pairs
/// are compared by their first elements first, if their first elements are equal, then they
/// are compared by their second elements.
/// If either TFirst or TSecond does not implement IComparable<T> or IComparable, then
/// an NotSupportedException is thrown, because the pairs cannot be compared.
///
/// The pair to compare to.
/// An integer indicating how this pair compares to . Less
/// than zero indicates this pair is less than . Zero indicate this pair is
/// equals to . Greater than zero indicates this pair is greater than
/// .
/// Either FirstSecond or TSecond is not comparable
/// via the IComparable<T> or IComparable interfaces.
public int CompareTo(Pair other)
{
try {
int firstCompare = firstComparer.Compare(First, other.First);
if (firstCompare != 0)
return firstCompare;
else
return secondComparer.Compare(Second, other.Second);
}
catch (ArgumentException) {
// Determine which type caused the problem for a better error message.
if (!typeof(IComparable).IsAssignableFrom(typeof(TFirst)) &&
!typeof(System.IComparable).IsAssignableFrom(typeof(TFirst))) {
throw new NotSupportedException(string.Format(Strings.UncomparableType, typeof(TFirst).FullName));
}
else if (!typeof(IComparable).IsAssignableFrom(typeof(TSecond)) &&
!typeof(System.IComparable).IsAssignableFrom(typeof(TSecond))) {
throw new NotSupportedException(string.Format(Strings.UncomparableType, typeof(TSecond).FullName));
}
else
throw; // Hmmm. Unclear why we got the ArgumentException.
}
}
///
/// Compares this pair to another pair of the some type. The pairs are compared by using
/// the IComparable<T> or IComparable interface on TFirst and TSecond. The pairs
/// are compared by their first elements first, if their first elements are equal, then they
/// are compared by their second elements.
/// If either TFirst or TSecond does not implement IComparable<T> or IComparable, then
/// an NotSupportedException is thrown, because the pairs cannot be compared.
///
/// The pair to compare to.
/// An integer indicating how this pair compares to . Less
/// than zero indicates this pair is less than . Zero indicate this pair is
/// equals to . Greater than zero indicates this pair is greater than
/// .
/// is not of the correct type.
/// Either FirstSecond or TSecond is not comparable
/// via the IComparable<T> or IComparable interfaces.
int IComparable.CompareTo(object obj)
{
if (obj is Pair)
return CompareTo((Pair)obj);
else
throw new ArgumentException(Strings.BadComparandType, "obj");
}
///
/// Returns a string representation of the pair. The string representation of the pair is
/// of the form:
/// First: {0}, Second: {1}
/// where {0} is the result of First.ToString(), and {1} is the result of Second.ToString() (or
/// "null" if they are null.)
///
/// The string representation of the pair.
public override string ToString()
{
return string.Format("First: {0}, Second: {1}", (First == null) ? "null" : First.ToString(), (Second == null) ? "null" : Second.ToString());
}
///
/// Determines if two pairs are equal. Two pairs are equal if the first and second elements
/// both compare equal using IComparable<T>.Equals or object.Equals.
///
/// First pair to compare.
/// Second pair to compare.
/// True if the pairs are equal. False if the pairs are not equal.
public static bool operator ==(Pair pair1, Pair pair2)
{
return firstEqualityComparer.Equals(pair1.First, pair2.First) && secondEqualityComparer.Equals(pair1.Second, pair2.Second);
}
///
/// Determines if two pairs are not equal. Two pairs are equal if the first and second elements
/// both compare equal using IComparable<T>.Equals or object.Equals.
///
/// First pair to compare.
/// Second pair to compare.
/// True if the pairs are not equal. False if the pairs are equal.
public static bool operator !=(Pair pair1, Pair pair2)
{
return !(pair1 == pair2);
}
///
/// Converts a Pair to a KeyValuePair. The Key part of the KeyValuePair gets
/// the First element, and the Value part of the KeyValuePair gets the Second
/// elements.
///
/// Pair to convert.
/// The KeyValuePair created from .
public static explicit operator KeyValuePair(Pair pair)
{
return new KeyValuePair(pair.First, pair.Second);
}
///
/// Converts this Pair to a KeyValuePair. The Key part of the KeyValuePair gets
/// the First element, and the Value part of the KeyValuePair gets the Second
/// elements.
///
/// The KeyValuePair created from this Pair.
public KeyValuePair ToKeyValuePair()
{
return new KeyValuePair(this.First, this.Second);
}
///
/// Converts a KeyValuePair structure into a Pair. The
/// First element gets the Key, and the Second element gets the Value.
///
/// The KeyValuePair to convert.
/// The Pair created by converted the KeyValuePair into a Pair.
public static explicit operator Pair(KeyValuePair keyAndValue)
{
return new Pair(keyAndValue);
}
}
}