C# 应该是合理的<;T>';s Equals()可以通过IComparable实现<;T>';s CompareTo()?

C# 应该是合理的<;T>';s Equals()可以通过IComparable实现<;T>';s CompareTo()?,c#,C#,我一直在互联网上寻找答案,但我发现的是: 编辑:添加一些项目以响应答案 对于足够的 我应该重载Equals(),GetHashCode(),==和=在一起 我应该通过实现来减少冗余=通过== 我应该封班 对于IComparable 我应该一起重载Equals(),GetHashCode(),,= 事实上,建议在执行此操作时实现IEquatable 重载IComparable的非泛型版本 CompareTo()==0应表示Equals()==true 所以我一直在想: public b

我一直在互联网上寻找答案,但我发现的是:

编辑:添加一些项目以响应答案

  • 对于足够的

    • 我应该重载
      Equals()
      GetHashCode()
      ==
      =在一起
    • 我应该通过实现
      来减少冗余=通过
      ==
    • 我应该封班
  • 对于IComparable

    • 我应该一起重载
      Equals()
      GetHashCode()
      =
    • 事实上,建议在执行此操作时实现IEquatable
    • 重载IComparable的非泛型版本
    • CompareTo()==0
      应表示
      Equals()==true
所以我一直在想:

public bool Equals(T other)
{
    if ((object)other == null)
    {
        return false;
    }

    return CompareTo(other) == 0;
}
我是忽略了什么还是这样可以?

x.CompareTo(y)==0
并不意味着
x.Equals(y)==true

x.CompareTo(y)==0
仅表示在对元素
x
y
进行排序时,项目出现

例如,给定以下类:

public class Person
{
    public string Name { get; set;}
    public string Passport { get; set; }
}

var me = new Person { Name = "Diogo Castro", Passport = "12345" };
var someoneElse = new Person { Name = "Diogo Castro", Passport = "67890" }; 
按姓名(字母顺序)对这两个人进行排序时,您希望
me.CompareTo(someone)
返回0,因为他们的姓名相同。因此,它们出现的顺序无关紧要

但是,您希望
me.Equals(someone)
返回false,因为它们不是同一个人。

根据
IEquatable
界面中的说明,应使用确定两个对象是否相等。根据
i可比较的
界面应用于支持对象的比较,以确定对象的顺序

当然,您可以像以前一样实现
Equals
方法,但这样做会在两个不同的事物之间创建依赖关系。两个对象的相等及其顺序

它总是取决于你如何看待对象本身。这可能是(一个愚蠢的例子,我知道)你指定两辆车是相同的,如果它们有相同的
发动机类型
,相同的
发动机功率
等等。如果你想订购,你可以通过比较发动机的功率来订购,而不是型号和其他一切。因此,如果对象本身包含相同的值/引用,则可以实现
Equals
以返回true;如果对象本身可能只有相同的功率,但可能有不同的引擎类型,则可以实现
compare to
,以此类推

(旁注:这就是为什么我更喜欢与之进行比较。)

,微软C#编译器团队的前开发人员:

  • 在C语言中有九种比较方法:
    =
    =
    =
    object.Equals(object)
    IEquatable.Equals(T)
    i可比较。与(T)
  • 理想情况下,这些都应该彼此一致。也就是说,如果
    x==y
    为真,则
    x
    为假,但
    x0;}
    公共静态布尔运算符=0;}
    公共静态布尔运算符==(自然x,自然y){返回CompareTo(x,y)==0;}
    公共静态布尔运算符=(自然x,自然y){返回CompareTo(x,y)!=0;}
    public override bool Equals(object obj){返回CompareTo(这个,obj作为自然对象)==0;}
    公共布尔等于(自然x){返回CompareTo(this,x)==0;}
    私有静态整数比较(自然x,自然y){…}
    
    看看OrangeDog的回答。这是针对Java的,但问题类似。IEqutable用于表示相等,而IComparable用于对对象进行排序。另外,您正在实现的IEquatable和IComparable是否也适用于同一个类?如果是,无论出于何种原因,我不认为重用CompareTo实现相等会有什么问题。相反,
    Equals()==true
    意味着
    CompareTo()==0
    。事实并非总是相反,我不同意
    Equals()==true
    可能与
    CompareTo()==0
    不一样-详细信息请参见我的答案。作为旁注,.Hahaha,你的例子比我的好得多:-“
    x.CompareTo(y)==0
    意味着
    x.Equals(y)==true
    ”那么,只有Java是正确的吗?@Johannes我认为,不管使用哪种语言,它都是不正确的。但老实说,JavaDoc提出的相反的事实很有趣。如果
    x.CompareTo(y)==0
    并不意味着
    x.Equals(y)
    ,那么我认为类代表的东西不是自然的、本质上可排序的身份(相等),它不应该实现
    IComparable
    。即使是日历事件这样的事件,似乎天生可以按时间排序,也不应该是可比较的,因为它们没有天生的顺序,因为同时发生的两个事件彼此不相等。如果“排序时,排序在一起的项目彼此不相等”,则排序需要范围上下文,请改用
    IComparer
    。以您自己的示例为例,一个人并非天生可以排序,您是否按
    姓名
    、年龄、身高、智力、温度或其他方式排序完全是任意的。因此,您的
    Person
    类完全不适合
    IComparable
    ,相反,您应该使用
    公共类PersonNameComparer:IComparer
    。您的示例不是反例,而是支持我的情况,即通过
    IComparable
    比较0的对象也应该相等。Equals应该测试两个对象是否相等,而不管它们的含义如何(即测试它们的内部字段是否相等)。在您的示例中,Equals不尊重其com
    public int CompareTo(Natural x) { return CompareTo(this, x); }
    public static bool operator <(Natural x, Natural y) { return CompareTo(x, y) < 0; }
    public static bool operator >(Natural x, Natural y) { return CompareTo(x, y) > 0; }
    public static bool operator <=(Natural x, Natural y) { return CompareTo(x, y) <= 0; }
    public static bool operator >=(Natural x, Natural y) { return CompareTo(x, y) >= 0; }
    public static bool operator ==(Natural x, Natural y) { return CompareTo(x, y) == 0; }
    public static bool operator !=(Natural x, Natural y) { return CompareTo(x, y) != 0; } 
    public override bool Equals(object obj) { return CompareTo(this, obj as Natural) == 0; }
    public bool Equals(Natural x) { return CompareTo(this, x) == 0; }
    
    private static int CompareTo(Natural x, Natural y) { ... }