I'm storing users table-column-configuration in a simple class:
public class ColumnUserSetting : IComparable<ColumnUserSetting>
{
public String TableWrapperName { get; set; }
public String ColumnName { get; set; }
public Boolean Enabled { get; set; }
public int Width { get; set; }
public int Position { get; set; }
}
}
these classes are stored inside a SortedSet - so, it needed to implement IComparable<>
, which i implemented based on position, as the documentation says its about position comparison - nothing said they can't be the same:
public class ColumnUserSetting : IComparable<ColumnUserSetting>
{
public String TableWrapperName { get; set; }
public String ColumnName { get; set; }
public Boolean Enabled { get; set; }
public int Width { get; set; }
public int Position { get; set; }
public int CompareTo(ColumnUserSetting other)
{
if (other.Position == this.Position) return 0;
if (other.Position > this.Position) return -1;
return 1;
}
}
However, this seems to behave like "equals" in the same run. Entries having the SAME Position are overwriting each other within the set. (Even if table an column is different)
the MSDN Docu says: "Types that implement IComparable must override Equals. Types that override Equals must also override GetHashCode; otherwise, Hashtable might not work correctly."
So, I implemented these two as well, with no success:
public class ColumnUserSetting : IComparable<ColumnUserSetting>
{
public String TableWrapperName { get; set; }
public String ColumnName { get; set; }
public Boolean Enabled { get; set; }
public int Width { get; set; }
public int Position { get; set; }
public int CompareTo(ColumnUserSetting other)
{
if (other.Position == this.Position) return 0;
if (other.Position > this.Position) return -1;
return 1;
}
public override bool Equals(object obj)
{
if (!(obj is ColumnUserSetting))
return false;
ColumnUserSetting cus = (ColumnUserSetting)obj;
return (this.TableWrapperName == cus.TableWrapperName &&
this.ColumnName == cus.TableWrapperName &&
this.Enabled == cus.Enabled &&
this.Width == cus.Width &&
this.Position == cus.Position);
}
public override int GetHashCode()
{
var hashcode = 352033288;
hashcode = hashcode * -1521134295 + TableWrapperName.GetHashCode();
hashcode = hashcode * -1521134295 + ColumnName.GetHashCode();
hashcode = hashcode * -1521134295 + Enabled.GetHashCode();
hashcode = hashcode * -1521134295 + Width.GetHashCode();
hashcode = hashcode * -1521134295 + Position.GetHashCode();
return hashcode;
}
}
Only way to get the SortedSet to work as expected was to handle entries of different tables with another result from CompareTo
:
public int CompareTo(ColumnUserSetting other)
{
if (this.TableWrapperName != other.TableWrapperName)
return String.Compare(this.TableWrapperName, other.TableWrapperName);
if (other.Position == this.Position) return 0;
if (other.Position > this.Position) return -1;
return 1;
}
Is this a bug or a feature?
If we inspect the reference source code for SortedSet
, we can look at the implementation of AddIfNotPresent()
. This returns true
if an item was added, or false
if the item already exists.
Near the start of the method, we have:
int order = 0;
while (current != null) {
order = comparer.Compare(item, current.Item);
if (order == 0) {
// We could have changed root node to red during the search process.
// We need to set it to black before we return.
root.IsRed = false;
return false;
}
So it is only calling the Compare()
method to see if the item is the same. Thus, for your class, it only cares if Position
is the same. If it is, the new item is not added.
I would say that this is a deliberate design - it's not a bug.
You will have to change your CompareTo()
implementation so that it compares all the same elements as the Equals()
. Just call each element's CompareTo()
to do a complete ordering.