何の問題はIStructuralEquatableとIStructuralComparable解決?
-
25-09-2019 - |
質問
にのってこれら二つのインタフェース、および複数の関連するクラスが追加されます。NET4.もう少し余計なっ;っくりとした複数のブログについて、だいたい何の問題も解決が難しい。NET4.
何に利用 IStructuralEquatable
や IStructuralComparable
?
解決
.NETのすべての種類は、デフォルトでは、ための2つのタイプを比較しObject.Equals()
メソッドをサポートしての の参照の等価のの。しかし、時には、また、望ましいの の構造的平等ののための2つのタイプを比較することができるようにします。
この最良の例は、.NET 4で今IStructuralEquatable
インタフェースを実装する配列です。彼らはそれぞれの位置で同じ値を持つ項目の数が同じかどうか - これは参照の等価のため、または「構造的平等」のための2つの配列を比較しているかどうかを区別することが可能となります。ここでは例があります:
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 upvotesを持っているにもかかわらず、それは間違っています。 reflector'ing」たくさんの後、ここでは物事の私のテイクがあります。
特定のコンテナ(アレイ、タプル、匿名型)支持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;
}
}
}
今、私たちは、コンテナ内のコンテナ内のコンテナを持つアイテムをHashSetのを作ることができます。
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);
}
}
今、私たちは、容器内のカスタムコンテナ内のコンテナを持つアイテムをHashSetのを作ることができます。
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
ここでは、2つのインターフェイスの可能な使用法を示す別の例である:
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
インターフェースをスをするカスタマイズ比較チェックのための構造等の collectionオブジェ.
ことも明らかにすることをこのインタフェースに常駐 System.Collections
namespace.
F#は(.NET 4.ので、それらを使用して開始<のhref = "https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/collections.istructuralequatable-interface-%5Bfsharp%5D" のrel =」 nofollowをnoreferrer ">。ネット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
の結果は、 同じ配列を参照する二つの変数です。同様に、2つの別個のアレイは、意志 常に平等テストを-ない限り失敗は、カスタム等値比較子を使用します。フレームワーク 4.0これのことができます。配列の要素を比較する目的のために導入された1つ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