Sortedset not using custom equals

流过昼夜 提交于 2020-01-07 07:24:13

问题


My class implements IEquatable and IComparable. It then gets added to a sortedset.

The goal is to have it be sorted by its "Date" property and be equal if both "ID1" and "ID2" are the same.

The implemented methods:

public int CompareTo(MyClass other)
{
    return other.Date.CompareTo(Date);
}

public override int GetHashCode()
{
    unchecked
    {
        var hashCode = ID1;
        hashCode = (hashCode * 397) ^ ID2;
        return hashCode;
    }
}

public bool Equals(MyClass other)
{
    if (ReferenceEquals(null, other)) 
       return false;

    if (ReferenceEquals(this, other)) 
       return true;

    return ID1 == other.ID1
        && ID2 == other.ID2;
}

The resulting sortedset is correctly sorted, but there are still elements that should be equal and therefore not in the set. Using breakpoints it seems neither GetHashCode nor Equals get called.

Any tips on how to solve this?


回答1:


SortedSet uses CompareTo for both sorting and equality comparison.

There isn't an in-built ordered collection which will allow you to specify a different method to compare for equality in ordering than to compare for equality in maintaining distinctness. I'm not completely sure why this is, but it may be to do with the asssumptions behind the algorithms used for sorting.

If you want this behaviour, probably the simplest way to do it is wrap the underlying collection in its own class which will check for distinctness before adding new items to the collection.

You also need to be careful that items which are equal for sorting but not equal by your Equals method can both be added to the underlying collection. In your case, where the sorting is done by Date and the equality is done by ID1 and ID2 this might look something like:

public int CompareTo(MyClass other)
{
    var result = other.Date.CompareTo(Date);
    if(result != 0)
        return result;
    result = other.ID1.CompareTo(ID1);
    if(result != 0)
        return result;
    return other.ID2.CompareTo(ID2);
}

This imposes extra ordering if the dates are the same, but I wouldn't expect that to be a problem.

Alternatively, you can "cheat", by forcing items which are equal to compare as equal in sort position. This would probably best be moved to a custom IComparer, because it's not the normal sorting behaviour you want, outside a SortedSet:

public int CompareTo(MyClass other)
{
    if(other.Equals(this))
        return 0;

    var result = other.Date.CompareTo(Date);
    if(result != 0)
        return result;
    result = other.ID1.CompareTo(ID1);
    if(result != 0)
        return result;
    return other.ID2.CompareTo(ID2);
}

This would allow you to avoid having to create your own wrapper class around the collection, and is safer. It is rather hacky, though.



来源:https://stackoverflow.com/questions/24220369/sortedset-not-using-custom-equals

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!