Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equality of two structs in C#

Tags:

c#

I look for an equality between two instances of this struct.

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

This doesn't work. What am I missing?

        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);
like image 528
Frederic Avatar asked Jan 11 '10 14:01

Frederic


3 Answers

You should compare the contents of the Array in your Equality logic ...

Also, it is recommended that you implement IEquatable<T> interface on your struct, as this prevents boxing/unboxing issues in some cases. http://blogs.msdn.com/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object-s-equals-and-gethashcode.aspx

like image 26
Frederik Gheysels Avatar answered Oct 17 '22 11:10

Frederik Gheysels


I don't think there's anything built into the framework to do that for you, I'm afraid

In 4.0, there is:

StructuralComparisons.StructuralEqualityComparer.Equals(firstArray, secondArray);
like image 69
Sebastian Ullrich Avatar answered Oct 17 '22 10:10

Sebastian Ullrich


You're comparing the array references rather than their contents. ya and yb refer to different arrays. If you want to check the contents of the arrays, you'll have to do so explicitly.

I don't think there's anything built into the framework to do that for you, I'm afraid. Something like this should work though:

public static bool ArraysEqual<T>(T[] first, T[] second)
{
    if (object.ReferenceEquals(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;
}

As an aside, your structs are sort of mutable in that the array contents can be changed after the struct is created. Do you really need this to be a struct?

EDIT: As Nick mentioned in the comments, you should really override GetHashCode as well. Again, you'll need to get the contents from the arrays (and again, this will cause problems if the arrays get changed afterwards). Similar utility method:

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;
}
like image 41
Jon Skeet Avatar answered Oct 17 '22 11:10

Jon Skeet