这里的关键是意识到任何任意大小的对象集合都可以通过简单地将其视为一个 IEnumerable 来进行散列,该 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;
}
}
和等于:
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>
.