HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Is this an ok implementation of an UnorderedPair?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thisimplementationunorderedpair

Problem

I want to create pair, where new UnorderedPair(ObjA, ObjB) == UnorderedPair(ObjB, ObjA) returns true. I also want to avoid any (un)boxing.

Have I gone about this in the correct way?

public struct UnorderedPair : IEquatable>
{
    public T A;
    public T B;

    public UnorderedPair(T a, T b)
    {
        A = a;
        B = b;
    }

    public override int GetHashCode()
    {
        return A.GetHashCode() ^ B.GetHashCode();
    }

    public bool Equals(UnorderedPair other)
    {
        return (other.A.Equals(A) && other.B.Equals(B)) ||
               (other.A.Equals(B) && other.B.Equals(A));
    }

    public override bool Equals(object obj)
    {
        return Equals((UnorderedPair)obj);
    }

    public static bool operator ==(UnorderedPair a, UnorderedPair b)
    {
        return a.Equals(b);
    }

    public static bool operator !=(UnorderedPair a, UnorderedPair b)
    {
        return !(a == b);
    }
}

Solution

One thing: I would make the struct immutable since mutable structs have really bad unintended effects. Otherwise, this is a good, solid implementation.

public struct UnorderedPair : IEquatable>
{
    private readonly T a;

    private readonly T b;

    public UnorderedPair(T a, T b)
    {
        this.a = a;
        this.b = b;
    }

    public T A
    {
        get
        {
            return this.a;
        }
    }

    public T B
    {
        get
        {
            return this.b;
        }
    }

    public override int GetHashCode()
    {
        return this.a.GetHashCode() ^ this.b.GetHashCode();
    }

    public bool Equals(UnorderedPair other)
    {
        return (other.A.Equals(this.a) && other.B.Equals(this.b)) ||
               (other.A.Equals(this.b) && other.B.Equals(this.a));
    }

    public override bool Equals(object obj)
    {
        return this.Equals((UnorderedPair)obj);
    }

    public static bool operator ==(UnorderedPair a, UnorderedPair b)
    {
        return a.Equals(b);
    }

    public static bool operator !=(UnorderedPair a, UnorderedPair b)
    {
        return !(a == b);
    }
}


and because time marches on, here's a more compact and performant C# 7.2 version:

public readonly struct UnorderedPair : IEquatable>
{
    public UnorderedPair(in T a, in T b) => (this.A, this.B) = (a, b);

    public T A { get; }

    public T B { get; }

    public override int GetHashCode() => this.A.GetHashCode() ^ this.B.GetHashCode();

    public bool Equals(UnorderedPair other) => (other.A.Equals(this.A) && other.B.Equals(this.B))
        || (other.A.Equals(this.B) && other.B.Equals(this.A));

    public override bool Equals(object obj) => this.Equals((UnorderedPair)obj);

    public static bool operator ==(in UnorderedPair a, in UnorderedPair b) => a.Equals(b);

    public static bool operator !=(in UnorderedPair a, in UnorderedPair b) => !(a == b);
}

Code Snippets

public struct UnorderedPair<T> : IEquatable<UnorderedPair<T>>
{
    private readonly T a;

    private readonly T b;

    public UnorderedPair(T a, T b)
    {
        this.a = a;
        this.b = b;
    }

    public T A
    {
        get
        {
            return this.a;
        }
    }

    public T B
    {
        get
        {
            return this.b;
        }
    }

    public override int GetHashCode()
    {
        return this.a.GetHashCode() ^ this.b.GetHashCode();
    }

    public bool Equals(UnorderedPair<T> other)
    {
        return (other.A.Equals(this.a) && other.B.Equals(this.b)) ||
               (other.A.Equals(this.b) && other.B.Equals(this.a));
    }

    public override bool Equals(object obj)
    {
        return this.Equals((UnorderedPair<T>)obj);
    }

    public static bool operator ==(UnorderedPair<T> a, UnorderedPair<T> b)
    {
        return a.Equals(b);
    }

    public static bool operator !=(UnorderedPair<T> a, UnorderedPair<T> b)
    {
        return !(a == b);
    }
}
public readonly struct UnorderedPair<T> : IEquatable<UnorderedPair<T>>
{
    public UnorderedPair(in T a, in T b) => (this.A, this.B) = (a, b);

    public T A { get; }

    public T B { get; }

    public override int GetHashCode() => this.A.GetHashCode() ^ this.B.GetHashCode();

    public bool Equals(UnorderedPair<T> other) => (other.A.Equals(this.A) && other.B.Equals(this.B))
        || (other.A.Equals(this.B) && other.B.Equals(this.A));

    public override bool Equals(object obj) => this.Equals((UnorderedPair<T>)obj);

    public static bool operator ==(in UnorderedPair<T> a, in UnorderedPair<T> b) => a.Equals(b);

    public static bool operator !=(in UnorderedPair<T> a, in UnorderedPair<T> b) => !(a == b);
}

Context

StackExchange Code Review Q#8587, answer score: 5

Revisions (0)

No revisions yet.