這裏的關鍵是意識到任何任意大小的對象集合都可以通過簡單地將其視爲IEnumerable來散列,其哈希碼取決於枚舉的內容。
爲此,我簡單地創建了一個實現IEnumerable的ValueAwareEnumerable類。這個類在其唯一的構造函數中使用一個枚舉。然後它重寫GetHashCode()和Equals(),以便它們依賴於可枚舉的內容。 GetHashCode方法很簡單:
public override int GetHashCode()
{
unchecked
{
int hash = 983;
foreach (var item in _wrappedEnumerable)
if(item != null)
hash = hash * 457 + item.GetHashCode();
return hash;
}
}
和equals:
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (ValueAwareEnumerable<T>)) return false;
return Equals((ValueAwareEnumerable<T>) obj);
}
public bool Equals(ValueAwareEnumerable<T> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return _wrappedEnumerable.SequenceEqual(other);
}
的這裏需要注意的是,它取決於枚舉的順序上。如果需要,可以通過在迭代遍歷它之前簡單地使GetHashCode()和Equals()對枚舉進行排序來使其與順序無關。
要完成它,只添加一個擴展方法某處的好措施:
public static IEnumerable<T> ToValueAwareEnumerable<T>(this IEnumerable<T> enumerable)
{
return new ValueAwareEnumerable<T>(enumerable);
}
你可以做這樣的事情:
var dictionary = new Dictionary<IEnumerable<int>>();
var veryImportantNumbers = new[] { 5, 8, 13, 20, 3, 100, 55, -5, 0 };
dictionary[veryImportantNumbers.ToValueAwareEnumerable()] = "Pastrami";
這將任何數據類型工作,即使是混合數據類型,如果您將它們視爲IEnumerable<Object>
。
無論你選擇什麼,你都會冒着碰撞的危險。對於你的字符串版本,它可能可以忽略不計。 – 2012-04-13 19:14:32
是的,你永遠無法完全避免碰撞,因爲哈希碼只有有限數量的不同可能值。 – 2012-04-13 19:23:33
我會投票使用'GetHashCode()'的數學組合並將其用作關鍵字,並使其能夠很好地處理碰撞。例如'Dictionary>',如果列表包含多個對象,則比較它們以找到正確的對象。 –
Thymine
2012-04-13 20:55:47