Gleichheit zweier Strukturen in C #

Ich suche nach einer Gleichheit zwischen zwei Instanzen dieser Struktur.

public struct Serie { T[] X; double[] Y; public Serie(T[] x, double[] y) { X = x; Y = y; } public override bool Equals(object obj) { return obj is Serie && this == (Serie)obj; } public static bool operator ==(Serie s1, Serie s2) { return s1.X == s2.X && s1.Y == s2.Y; } public static bool operator !=(Serie s1, Serie s2) { return !(s1 == s2); } 

Das geht nicht. Was vermisse ich?

  double[] xa = { 2, 3 }; double[] ya = { 1, 2 }; double[] xb = { 2, 3 }; double[] yb = { 1, 2 }; Serie A = new Serie(xa, ya); Serie B = new Serie(xb, yb); Assert.AreEqual(A, B); 

Sie vergleichen die Array- Referenzen und nicht deren Inhalt. ya und yb beziehen sich auf verschiedene Arrays. Wenn Sie den Inhalt der Arrays überprüfen möchten, müssen Sie dies explizit tun.

Ich glaube nicht , dass etwas in den Rahmen eingebaut ist, um das für Sie zu tun, fürchte ich. So etwas sollte aber funktionieren:

 public static bool ArraysEqual(T[] first, T[] second) { if (first == second) { return true; } if (first == null || second == null) { return false; } if (first.Length != second.Length) { return false; } IEqualityComparer comparer = EqualityComparer.Default; for (int i = 0; i < first.Length; i++) { if (!comparer.Equals(first[i], second[i])) { return false; } } return true; } 

Abgesehen davon sind Ihre Strukturen in gewisser Weise veränderbar, da der Inhalt des Arrays nach dem Erstellen der Struktur geändert werden kann. Brauchen Sie das wirklich als Struktur?

BEARBEITEN: Wie Nick in den Kommentaren erwähnte, sollten Sie auch GetHashCode wirklich überschreiben. Auch hier müssen Sie den Inhalt aus den Arrays beziehen (und dies wiederum führt zu Problemen, wenn sich die Arrays danach ändern). Ähnliche Gebrauchsmethode:

 public static int GetHashCode(T[] array) { if (array == null) { return 0; } IEqualityComparer comparer = EqualityComparer.Default; int hash = 17; foreach (T item in array) { hash = hash * 31 + comparer.GetHashCode(item); } return hash; } 

Ich glaube nicht, dass etwas in den Rahmen eingebaut ist, um das für Sie zu tun, fürchte ich

In 4.0 gibt es:

 StructuralComparisons.StructuralEqualityComparer.Equals(firstArray, secondArray); 

Sie sollten den Inhalt des Arrays in Ihrer Gleichheitslogik vergleichen …

Es wird außerdem empfohlen, die IEquatable -Schnittstelle in Ihrer Struktur zu implementieren, da dies in einigen Fällen Box- / Unboxing-Probleme verhindert. http://blogs.msdn.com/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object-s-equals-and-gethashcode.aspx

Der Teil s1.Y == s2.Y prüft, ob es sich um zwei Referenzen auf dieselbe Array-Instanz handelt , nicht ob der Inhalt gleich ist. Trotz des Titels handelt es sich bei dieser Frage eigentlich um die Gleichheit der Array (-referenz) s.

Ein paar zusätzliche Hinweise: Da Sie überladen, sollten Sie Serie<> als unveränderlich entcasting. Aufgrund des eingebetteten Arrays würde ich sie statt einer Struktur zu einer class machen.

Das Aufrufen von == führt zu einer Referenzgleichheit in Arrays – sie vergleichen nicht den Inhalt ihrer Elemente. Dies bedeutet im Grunde, dass a1 == a2 nur dann true a1 == a2 , wenn genau dieselbe Instanz vorhanden ist.

Sie müssen Ihren operator == ändern, um den Inhalt des x Arrays zu bestimmen, nicht den Referenzwert.

Wenn Sie .NET 3.5 (mit Link) verwenden, können Sie Folgendes tun:

 public static bool operator ==(Serie s1, Serie s2) { return ((s1.X == null && s2.X == null) || s1.X.SequenceEquals( s2.X )) && s1.Y == s2.Y; } 

Wenn Sie einen tieferen Vergleich (über Referenzen hinaus) durchführen müssen, können Sie SequenceEquals mit einem benutzerdefinierten IEqualityComparer für den Typ von T versehen.

IEquatable sollten Sie auch die IEquatable Schnittstelle IEquatable für Ihre Struktur implementieren. Es hilft Ihrem Code, mit LINQ und anderen Teilen des .NET-Frameworks, die Objektvergleiche durchführen, besser zu arbeiten.

Sie können einen privaten Accessor für Ihre Struktur erstellen und CollectionAssert :

 [TestMethod()] public void SerieConstructorTest() { double[] xa = { 2, 3 }; double[] ya = { 1, 2 }; double[] xb = { 2, 3 }; double[] yb = { 1, 2 }; var A = new Serie_Accessor(xa, ya); var B = new Serie_Accessor(xb, yb); CollectionAssert.AreEqual(AX, BX); CollectionAssert.AreEqual(AY, BY); } 

Dieser Code funktioniert gut.

Verweise:

  • CollectionAssert.AreEqual-Methode
  • So erstellen Sie einen privaten Accessor