J'ai eu la même question. Quand j'ai couru LBushkin l'exemple, j'ai été surpris de voir que j'ai eu une réponse différente! Même si cette réponse a 8 upvotes, c'est mal. Après beaucoup de " réflecteur avec, ici, c'est ma façon de voir les choses.
Certains conteneurs (les tableaux, les tuples, les types anonymes) soutien IStructuralComparable et IStructuralEquatable.
IStructuralComparable prend en charge profonde, tri par défaut.
IStructuralEquatable prend en charge profonde, par défaut de hachage.
{Note qu' EqualityComparer<T>
prend en charge superficielle (1 seul niveau du conteneur), par défaut de hachage.}
Aussi loin que je vois c'est seulement exposée à travers la StructuralComparisons classe. La seule façon que je peux comprendre pour faire de cette utile est de faire de l' StructuralEqualityComparer<T>
de la classe helper comme suit:
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;
}
}
}
Maintenant, nous pouvons faire un HashSet avec des articles ayant des conteneurs à l'intérieur de conteneurs à l'intérieur des conteneurs.
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
Nous pouvons également apporter notre propre conteneur de bien jouer avec ces autres conteneurs par la mise en œuvre de ces interfaces.
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);
}
}
Maintenant, nous pouvons faire un HashSet avec des articles ayant des conteneurs à l'intérieur des conteneurs personnalisés dans les conteneurs.
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