【问题标题】:c# CompareTo not behaving as expected along with SortedSetsc#CompareTo 与 SortedSets 的行为不符合预期
【发布时间】:2020-09-02 16:04:17
【问题描述】:

我将 users 表列配置存储在一个简单的类中:

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

这些类存储在一个 SortedSet 中 - 因此,它需要实现 IComparable&lt;&gt;,这是我根据位置实现的,正如文档中所说的位置比较 - 没有说它们不能相同:

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

但是,这似乎在同一次运行中表现得像“等于”。具有相同位置的条目在集合中相互覆盖。 (即使表一列不同)

MSDN 文档说:“实现 IComparable 的类型必须覆盖 Equals。覆盖 Equals 的类型也必须覆盖 GetHashCode;否则,Hashtable 可能无法正常工作。

所以,我也实现了这两个,但没有成功:

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

让 SortedSet 按预期工作的唯一方法是处理来自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;
    }

这是错误还是功能?

【问题讨论】:

  • 你说条目是覆盖,但是比较为 0 时的动作不是覆盖?
  • 是的,没有仔细研究,只是注意到骗子不见了。但事实上,之后“未添加”重复项,保留添加的第一个条目。 (根据相同的 CompareTo-Result 重复,即使它们不相等)

标签: c# equals compareto icomparable


【解决方案1】:

如果我们检查reference source code 中的SortedSet,我们可以查看AddIfNotPresent() 的实现。如果添加了项目,则返回 true,如果项目已存在,则返回 false

在方法的开始处,我们有:

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

所以它只是调用Compare()方法来查看item是否相同。因此,对于您的班级,它只关心Position 是否相同。如果是,则不添加新项目。

我会说这是一个深思熟虑的设计 - 这不是一个错误。

您必须更改您的CompareTo() 实现,以便它比较与Equals() 相同的所有元素。只需调用每个元素的CompareTo() 即可完成排序。

【讨论】:

  • 至少它是一种方式,人们会期望什么 - 如何将具有相同“CreationDate”的项目添加到一个排序集中? ——如果他们不相等? :)
猜你喜欢
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多