Is this an ok implementation of an UnorderedPair?
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&lt;T&gt; : IEquatable&lt;UnorderedPair&lt;T&gt;&gt;
{
    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&lt;T&gt; other)
    {
        return (other.A.Equals(this.a) &amp;&amp; other.B.Equals(this.b)) ||
               (other.A.Equals(this.b) &amp;&amp; other.B.Equals(this.a));
    }

    public override bool Equals(object obj)
    {
        return this.Equals((UnorderedPair&lt;T&gt;)obj);
    }

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

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

and because time marches on, here's a more compact and performant C# 7.2 version:
public readonly struct UnorderedPair&lt;T&gt; : IEquatable&lt;UnorderedPair&lt;T&gt;&gt;
{
    public UnorderedPair(in T a, in T b) =&gt; (this.A, this.B) = (a, b);

    public T A { get; }

    public T B { get; }

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

    public bool Equals(UnorderedPair&lt;T&gt; other) =&gt; (other.A.Equals(this.A) &amp;&amp; other.B.Equals(this.B))
        || (other.A.Equals(this.B) &amp;&amp; other.B.Equals(this.A));

    public override bool Equals(object obj) =&gt; this.Equals((UnorderedPair&lt;T&gt;)obj);

    public static bool operator ==(in UnorderedPair&lt;T&gt; a, in UnorderedPair&lt;T&gt; b) =&gt; a.Equals(b);

    public static bool operator !=(in UnorderedPair&lt;T&gt; a, in UnorderedPair&lt;T&gt; b) =&gt; !(a == b);
}