2010-01-11 36 views
7

Busco una igualdad entre dos instancias de esta estructura.Igualdad de dos estructuras en C#

public struct Serie<T> 
{ 
    T[]   X; 
    double[] Y; 

    public Serie(T[] x, double[] y) 
    { 
     X = x; 
     Y = y; 
    } 

    public override bool Equals(object obj) 
    { 
     return obj is Serie<T> && this == (Serie<T>)obj; 
    } 
    public static bool operator ==(Serie<T> s1, Serie<T> s2) 
    { 
     return s1.X == s2.X && s1.Y == s2.Y; 
    } 
    public static bool operator !=(Serie<T> s1, Serie<T> s2) 
    { 
     return !(s1 == s2); 
    } 

Esto no funciona. ¿Qué me estoy perdiendo?

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

Respuesta

17

Usted está comparando la matriz referencias en lugar de su contenido. ya y yb se refieren a diferentes matrices. Si desea verificar el contenido de las matrices, tendrá que hacerlo explícitamente.

Creo que no hay algo incorporado en el marco para hacer eso por usted, me temo. Algo como esto debería funcionar sin embargo:

public static bool ArraysEqual<T>(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<T>.Default; 
    for (int i = 0; i < first.Length; i++) 
    { 
     if (!comparer.Equals(first[i], second[i])) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

Como acotación al margen, sus estructuras son una especie de mutable en el que el contenido de la matriz se pueden modificar una vez creada la estructura. ¿Realmente necesitas que esto sea una estructura?

EDITAR: Como Nick mencionó en los comentarios, también deberías anular GetHashCode. De nuevo, necesitará obtener el contenido de las matrices (y nuevamente, esto causará problemas si las matrices se cambian después). método de utilidad similares:

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

utilizando el método de extensión SequenceEqual() de LINQ. Puede comparar contenidos de la matriz. – LBushkin

+0

@LBushkin: Sí (debería haber mencionado eso), pero será algo ineficaz en comparación con una implementación que se basa en arreglos. –

+2

Posiblemente, pero tiendo a preferir la claridad sobre el rendimiento, a menos que haya un problema de rendimiento medido. Por curiosidad, ¿qué te hace creer que 'SequenceEquals' sería ineficiente? – LBushkin

2

La parte s1.Y == s2.Y pruebas si son 2 referencias al misma instancia de matriz, no si los contenidos son iguales. Entonces, a pesar del título, esta pregunta es realmente sobre la igualdad entre array (-referencia) s.

Algunos consejos adicionales: Ya que está sobrecargando should designSerie<> como inmutables y debido a la matriz incrustada, la convertiría en una clase en lugar de una estructura.

2

Llamando == realiza igualdad de referencia en arreglos - no se puede comparar el contenido de sus elementos. Esto significa básicamente que a1 == a2 sólo devolverá verdadero si la instancia exacta misma - que no es lo que quiere, creo ..

Usted necesita modificar su operator == a compere el contenido de la matriz x, no es valor de referencia.

Si está utilizando .NET 3.5 (con enlace) que puede hacer:

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

Si lo que necesita hacer la comparación profunda (más allá de las referencias), puede suministrar SequenceEquals con una costumbre para el tipo IEqualityComparer de T.

Probablemente también deba considerar implementar la interfaz IEquatable<T> para su estructura. Le ayudará a su código a funcionar mejor con LINQ y otras partes del framework .NET que realizan comparaciones de objetos.

1

Puede crear un descriptor de acceso privado para su estructura y el uso de 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<double>(xa, ya); 
    var B = new Serie_Accessor<double>(xb, yb); 
    CollectionAssert.AreEqual(A.X, B.X); 
    CollectionAssert.AreEqual(A.Y, B.Y); 
} 

Este código funciona bien.

Referencias:

5

No creo que haya nada integrado en el marco de hacer eso para usted, me temo

En 4.0, hay:

StructuralComparisons.StructuralEqualityComparer.Equals(firstArray, secondArray);