什么问题并IStructuralEquatable和IStructuralComparable解决?
-
25-09-2019 - |
题
我已经注意到这两个接口和若干相关课程,已经增加。净4.他们看起来有点多余;我读过几个博客的关于他们,但是我仍然不能找出什么问题,他们解决这个棘手之前。净4.
什么使用 IStructuralEquatable
和 IStructuralComparable
?
解决方案
所有类型中。净支持 Object.Equals()
法默认情况下,比较两种类型为 参考平等.然而,有时,它还希望能够比较两种类型为 结构上的平等.
最好的例子是阵列,这与。净4现在实施的 IStructuralEquatable
接口。这使得它能够区分是否比较两个阵列,用于参考平等,或"结构性平等"-它们是否具有相同的项目数量有同一价值在每个位置。这里有一个例子:
int[] array1 = new int[] { 1, 5, 9 };
int[] array2 = new int[] { 1, 5, 9 };
// using reference comparison...
Console.WriteLine( array1.Equals( array2 ) ); // outputs false
// now using the System.Array implementation of IStructuralEquatable
Console.WriteLine( StructuralComparisons.StructuralEqualityComparer.Equals( array1, array2 ) ); // outputs true
其他类型的实现结构平等/可比性,包括组和匿名的类型--这两者都显然从中受益的能力进行比较的基础上他们的结构和内容。
一个问题,你没有要求为:
为什么我们
IStructuralComparable
和IStructuralEquatable
当时那里已经 存在的IComparable
和IEquatable
接口?
回答我提供的是,在一般情况下,它的期望之间的区别参考对比和结构性比较。它的正常预期,如果你执行 IEquatable<T>.Equals
你也将复盖 Object.Equals
是一致的。在这种情况下你会如何支持这两个参考和结构的平等?
其他提示
我有同样的问题。当我跑LBushkin的例子中,我惊讶地看到,我得到了一个不同的答案!虽然这个问题的答案有8个"顶",这是错误的。经过大量的反射器清,这里是我的拿上东西。
某些容器(阵列,组,匿名的类型)支持IStructuralComparable和IStructuralEquatable.
IStructuralComparable支持深,默认排序。
IStructuralEquatable支持深,默认哈希。
{注意, EqualityComparer<T>
支持浅的(只有1容器的水平)、默认哈希。}
就我看到的这只是通过StructuralComparisons类。只有这样我才能想出来做这个有用的是使 StructuralEqualityComparer<T>
帮助类如下:
public class StructuralEqualityComparer<T> : IEqualityComparer<T>
{
public bool Equals(T x, T y)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(x,y);
}
public int GetHashCode(T obj)
{
return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
}
private static StructuralEqualityComparer<T> defaultComparer;
public static StructuralEqualityComparer<T> Default
{
get
{
StructuralEqualityComparer<T> comparer = defaultComparer;
if (comparer == null)
{
comparer = new StructuralEqualityComparer<T>();
defaultComparer = comparer;
}
return comparer;
}
}
}
现在我们可以做的。与项目具有容器之内容器,内容器。
var item1 = Tuple.Create(1, new int[][] { new int[] { 1, 2 }, new int[] { 3 } });
var item1Clone = Tuple.Create(1, new int[][] { new int[] { 1, 2 }, new int[] { 3 } });
var item2 = Tuple.Create(1, new int[][] { new int[] { 1, 3 }, new int[] { 3 } });
var set = new HashSet<Tuple<int, int[][]>>(StructuralEqualityComparer<Tuple<int, int[][]>>.Default);
Console.WriteLine(set.Add(item1)); //true
Console.WriteLine(set.Add(item1Clone)); //false
Console.WriteLine(set.Add(item2)); //true
我们也可以使我们自己的容器播放以及与这些其他的集装箱通过实施这些接口。
public class StructuralLinkedList<T> : LinkedList<T>, IStructuralEquatable
{
public bool Equals(object other, IEqualityComparer comparer)
{
if (other == null)
return false;
StructuralLinkedList<T> otherList = other as StructuralLinkedList<T>;
if (otherList == null)
return false;
using( var thisItem = this.GetEnumerator() )
using (var otherItem = otherList.GetEnumerator())
{
while (true)
{
bool thisDone = !thisItem.MoveNext();
bool otherDone = !otherItem.MoveNext();
if (thisDone && otherDone)
break;
if (thisDone || otherDone)
return false;
if (!comparer.Equals(thisItem.Current, otherItem.Current))
return false;
}
}
return true;
}
public int GetHashCode(IEqualityComparer comparer)
{
var result = 0;
foreach (var item in this)
result = result * 31 + comparer.GetHashCode(item);
return result;
}
public void Add(T item)
{
this.AddLast(item);
}
}
现在我们可以做的。与项目具有集装箱内的定制集装箱内,集装箱。
var item1 = Tuple.Create(1, new StructuralLinkedList<int[]> { new int[] { 1, 2 }, new int[] { 3 } });
var item1Clone = Tuple.Create(1, new StructuralLinkedList<int[]> { new int[] { 1, 2 }, new int[] { 3 } });
var item2 = Tuple.Create(1, new StructuralLinkedList<int[]> { new int[] { 1, 3 }, new int[] { 3 } });
var set = new HashSet<Tuple<int, StructuralLinkedList<int[]>>>(StructuralEqualityComparer<Tuple<int, StructuralLinkedList<int[]>>>.Default);
Console.WriteLine(set.Add(item1)); //true
Console.WriteLine(set.Add(item1Clone)); //false
Console.WriteLine(set.Add(item2)); //true
这里是另一个例子,说明了可能使用的两个接口:
var a1 = new[] { 1, 33, 376, 4};
var a2 = new[] { 1, 33, 376, 4 };
var a3 = new[] { 2, 366, 12, 12};
Debug.WriteLine(a1.Equals(a2)); // False
Debug.WriteLine(StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2)); // True
Debug.WriteLine(StructuralComparisons.StructuralComparer.Compare(a1, a2)); // 0
Debug.WriteLine(StructuralComparisons.StructuralComparer.Compare(a1, a3)); // -1
本说明的 IStructuralEquatable
接口 说(在"备注"部分):
的
IStructuralEquatable
接口使你能够实现自定义的比较检查结构的平等 收集对象.
这也是清楚的事实,这种接口居住在这 System.Collections
名字空间。
F#开始使用它们。净4.( .净2在这里)
这些接口是至关重要的F#
let list1 = [1;5;9]
let list2 = List.append [1;5] [9]
printfn "are they equal? %b" (list1 = list2)
list1.GetType().GetInterfaces().Dump()
C#一言以蔽之 书:
因为列为一类,列总是(己)
reference types
, 无论 该阵列的元件的类型。这意味着声明arrayB = arrayA
结果, 在两个变量的参考同一阵列。同样,两个不同的阵列会 总是失败的一个平等的试验,除非你使用一个自定义的平等比较器。框架 4.0介绍了一个用于该目的比较元件阵列,你可以 访问过StructuralComparisons
类型。
object[] a1 = { "string", 123, true};
object[] a2 = { "string", 123, true};
Console.WriteLine(a1 == a2); // False
Console.WriteLine(a1.Equals(a2)); // False
IStructuralEquatable se1 = a1;
Console.WriteLine(se1.Equals(a2, StructuralComparisons.StructuralEqualityComparer)); // True
Console.WriteLine(StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2)); // True
object[] a3 = {"string", 123, true};
object[] a4 = {"string", 123, true};
object[] a5 = {"string", 124, true};
IStructuralComparable se2 = a3;
Console.WriteLine(se2.CompareTo(a4, StructuralComparisons.StructuralComparer)); // 0
Console.WriteLine(StructuralComparisons.StructuralComparer.Compare(a3, a4)); // 0
Console.WriteLine(StructuralComparisons.StructuralComparer.Compare(a4, a5)); // -1
Console.WriteLine(StructuralComparisons.StructuralComparer.Compare(a5, a4)); // 1