是否存在类似于Tuple的.NET内置结构(或建议的方法来构建一个),它是关于等式和哈希码的顺序不变的?
下面的代码具有预期的ishashequal = false,我正在寻找的结构将返回true。
var dict = new Dictionary<Tuple<char, char>, int>();
var x = new Tuple<char, char>('a', 'b');
var y = new Tuple<char, char>('b', 'a');
dict.Add(x, 1);
bool isequal = dict.ContainsKey(y);
答案 0 :(得分:-1)
是否存在类似于Tuple的.NET内置结构(或建议的方法来构建一个),它是关于等式和哈希码的顺序不变的?
没有。如果有的话就会被打破。
通常会给出“密钥的哈希码不能改变”的过度简化,这是错误的。实际上,“用作密钥时密钥必须不会改变”,哈希代码不会改变应该反映出来。如果某些内容发生变化,会改变其与其他项目的比较方式,那么哈希码必须才能反映出来。当它被用作密钥时,不得发生这种情况,但这意味着密钥不得更改。否则,如果您创建了一个对象,并将其更改为然后将其用作键,则无效。
好的,所以改变你的问题
是否存在类似于Tuple的.NET内置结构(或建议的构建方法),关于相等和哈希码的顺序不变[当组件项不变时]?
是的, Tuple 就是一个例子。与 ValueTuple 和由相同部分组成的匿名对象一样。
下面的代码具有预期的ishashequal = false,我正在寻找的结构将返回true
这又是一个不同的东西。元组是给定数量元素的有限序列。作为一个序列意味着秩序是显着的。我们不希望元组(a, b)
与(b, a)
哈希相同,因为(a, b)
是与(b, a)
不同的元组,所以不能认为它是平等的(理想情况下)但不是严格的要求)不会有相同的哈希码。
确实Tuple<int, string>
根本不能在不同的订单中使用相同的元素。
Tuple
表示元组,但您描述的是使用有限集。有限集{a, b}
与有限集{b, a}
相同,因为顺序不重要。
你需要做两件事之一。
创建一个结构来表示一组有限的两个元素
public sealed class FiniteSet2<T> : IEquatable<FiniteSet2<T>>
{
public T First { get; }
public T Second { get; }
public FiniteSet2(T first, T second)
{
First = first;
Second = second;
}
public bool Equals(FiniteSet2<T> other)
{
if ((object)other != null)
{
return false;
}
// Test for same order.
if (EqualityComparer<T>.Default.Equals(First, other.First))
{
return EqualityComparer<T>.Default.Equals(Second, other.Second);
}
// Test for different order.
return EqualityComparer<T>.Default.Equals(First, other.Second)
&& EqualityComparer<T>.Default.Equals(Second, other.First)
}
public override bool Equals(object obj) => Equals(obj as FiniteSet2<T>);
// Deliberately matches elements in different order.
public override int GetHashCode() => First.GetHashCode() ^ Second.GetHashCode();
}
或者,如果您确实需要使用元组,请定义适当的比较器:
public sealed class CompareAsSetEqualityComparer<T> : IEqualityComparer<Tuple<T, T>>
{
public bool Equals(Tuple<T, T> x, Tuple<T, T> y)
{
if ((object)x == y)
{
return true;
}
if ((object)x == null | (object)y == null)
{
return false;
}
if (EqualityComparer<T>.Default.Equals(x.Item1, y.Item1))
{
return EqualityComparer<T>.Default.Equals(x.Item2, y.Item2);
}
return EqualityComparer<T>.Default.Equals(x.Item1, y.Item2)
&& EqualityComparer<T>.Default.Equals(x.Item2, y.Item1);
}
public int GetHashCode(Tuple<T, T> obj) =>
obj == null ? 0 : obj.Item1.GetHashCode() ^ obj.Item2.GetHashCode();
}
当然,如果元素是引用类型,它们本身就可以变异,这仍然会改变其他不可变的集合或元组。
(旁白:最近抖动的改善意味着,当序列EqualityComparer<T>.Default
被内联时,记忆EqualityComparer<T>.Default.Equals(…)
不再有意义。)