C#中两个结构的相等性

时间:2010-01-11 14:05:22

标签: 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);
    }

这不起作用。我错过了什么?

        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);

6 个答案:

答案 0 :(得分:19)

您正在比较数组引用而不是它们的内容。 yayb指的是不同的数组。如果要检查数组的内容,则必须明确地执行此操作。

我不会认为框架内置了任何内容为你做这件事,我很害怕。这样的事情应该有效:

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;
}

顺便说一下,你的结构有点可变,因为在创建结构后可以更改数组内容。你真的需要这个结构吗?

编辑:正如Nick在评论中提到的那样,你也应该覆盖GetHashCode。同样,您需要从数组中获取内容(同样,如果数组之后发生更改,这将导致问题)。类似的实用方法:

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;
}

答案 1 :(得分:6)

  

我不认为框架中有任何东西可以为你做这件事,我害怕

在4.0中,有:

StructuralComparisons.StructuralEqualityComparer.Equals(firstArray, secondArray);

答案 2 :(得分:5)

您应该在Equality logic ...

中比较数组的内容

此外,建议您在结构上实现IEquatable<T>接口,因为这可以防止在某些情况下出现装箱/拆箱问题。 http://blogs.msdn.com/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object-s-equals-and-gethashcode.aspx

答案 3 :(得分:2)

部分s1.Y == s2.Y测试它们是否是对相同数组实例的2个引用,而不是内容相等。所以尽管有标题,这个问题实际上是关于数组(-reference)s之间的相等性。

一些额外的建议:由于你将should design Serie<>重载为不可变的,因为嵌入式数组我会把它变成一个类而不是一个结构。

答案 4 :(得分:2)

调用==在数组上执行引用相等 - 它们不会比较其元素的内容。这基本上意味着a1 == a2只会返回true,如果完全相同的实例 - 这不是你想要的,我认为..

您需要修改operator ==以主持x数组的内容,而不是它的参考值。

如果你使用的是.NET 3.5(带链接),你可以这样做:

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;
}

如果您需要进行深度比较(超出参考范围),则可以为{T}类型的SequenceEquals提供自定义IEqualityComparer

您可能还应该考虑为您的struct实现IEquatable<T>接口。它将帮助您的代码更好地使用LINQ和执行对象比较的.NET框架的其他部分。

答案 5 :(得分:1)

您可以为结构创建私人访问者并使用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);
}

此代码工作正常。

参考文献: