C# 使Equals成为常用方法的目的是什么?

C# 使Equals成为常用方法的目的是什么?,c#,language-design,C#,Language Design,这不是一个如何实现的问题,而是这个方法的目的是什么?我的意思是——好吧,我知道搜索时需要它,但为什么它被作为“对象”类的方法隐藏呢 故事是这样的——我有一些类,它们的对象在默认情况下是不可比较的(在逻辑意义上)。每次要比较/搜索它们时,都必须准确指定匹配的方式。在这种情况下,最好是: 没有像Equals这样普遍存在的方法,问题解决了,没有程序员(我的类的用户)会因为在搜索时忽略自定义匹配而陷入陷阱 但是因为我不能改变C# 隐藏继承的、不需要的方法以防止调用(编译时) 但这也需要更改为C# 重

这不是一个如何实现的问题,而是这个方法的目的是什么?我的意思是——好吧,我知道搜索时需要它,但为什么它被作为“对象”类的方法隐藏呢

故事是这样的——我有一些类,它们的对象在默认情况下是不可比较的(在逻辑意义上)。每次要比较/搜索它们时,都必须准确指定匹配的方式。在这种情况下,最好是:

  • 没有像Equals这样普遍存在的方法,问题解决了,没有程序员(我的类的用户)会因为在搜索时忽略自定义匹配而陷入陷阱

    但是因为我不能改变C#

  • 隐藏继承的、不需要的方法以防止调用(编译时)

    但这也需要更改为C#

  • 重写等于并抛出异常——至少在运行时通知程序员

  • 所以我之所以这样问,是因为我被迫丑陋(c),因为(b)是不可能的,因为缺少(a)


    简言之,强制所有对象具有可比性(相等)的原因是什么?对我来说,这是一个太过分的假设。提前感谢您的启示:-)。

    我同意这在.NET和Java中基本上都是一个错误。对于
    GetHashCode
    ,情况也是如此,每个对象都有一个监视器

    不可否认,在泛型出现之前,它更有意义——但在泛型中,重写
    Equals(object)
    总是感觉非常可怕


    我刚才说过-你可能会发现帖子和评论都很有趣。

    你忘记了选项4:什么都不做,让默认的引用相等。我觉得没什么大不了的。即使使用自定义匹配选项,您也可以选择默认选项(我选择最严格的选项)并使用它来实现Equals()。

    假设有人有一个动物列表,并且希望比较两个项目:一个是Cat实例,一个是Dog实例。如果询问Cat实例是否与Dog实例相同,则Cat抛出InvalidTypeException或简单地说“不,它不相等”是否更有意义

    Equals方法应遵守两条规则:

  • 等式的互易性:对于任何X和Y,当且仅当Y等于(X)为真时,X等于(Y)才为真。
  • Liskov替换原理:如果类Q源于P,可以用Q完成的运算也可以用P完成。 这些共同意味着,如果Q从p派生,那么p类型的对象必须能够调用Q类型的对象上的Equals,这反过来意味着Q类型的对象必须能够调用p类型的对象上的Equals。此外,如果R也从p派生,类型为Q的对象必须能够对类型为R的对象调用Equals(无论R是否与Q相关)


    虽然并非严格要求所有对象都实现Equals,但对于所有类来说,拥有一个Equals(对象)要比拥有针对不同基类型的各种Equals方法干净得多,所有这些方法都必须用相同的语义覆盖以避免奇怪的行为

    编辑/补遗

    Equals的存在就是为了回答这个问题:给定两个对象引用X和Y,对象X能保证不使用ReferenceEquals、Reflection等的外部代码不能显示X和Y不引用同一个对象实例吗?对于任何对象X,X.Equals(X)必须为真,因为外部代码不可能显示X与X不是同一实例。此外,如果X.Equals(Y)为“合法”真,则Y.Equals(X)也必须为真;如果不是,那么X.Equals(X)(这是真的)与Y.Equals(X)不匹配的事实将是一个明显的差异,这意味着X.Equals(Y)应该是假的

    对于浅显易变的类型,如果X和Y引用不同的对象实例,通常可以通过对X进行突变并观察Y(*)中是否发生相同的突变来证明这一点。如果这种变异可以用来证明X和Y是不同的对象实例,那么X.Equals(Y)应该返回true。包含相同字符的两个字符串对象将报告它们自己相等的原因不仅仅是因为它们在比较时恰好包含相同的字符,更重要的是,如果一个字符串对象的所有实例都替换为另一个字符串对象,则只有使用ReferenceEquals、Reflection或其他类似技巧的代码,我甚至会注意到


    (*)可能有两个不同但不可区分的浅可变类实例X和Y,这两个实例都互相引用,这样,会变异一个的方法也会变异另一个。如果外部代码无法区分实例,则可以合法地让X.Equals(Y)报告true(反之亦然)。另一方面,我想不出这样一个类比X和Y都持有对共享可变对象的不可变引用的类更有用。注意,X.Equals(Y)并不要求X和Y是不可变的;它只要求应用于X的任何突变都会对Y产生相同的影响。

    Nice post!我从来没有真正地指出这一点,但事实上,在数十个类中,可能有一个类实际上需要平等语义。在这些情况下,它通常是来自应用程序规范的等式。起初.NET从JAVA复制了许多东西。我想知道除了与原型的相似性之外,在继承树的根中“拥有”这些东西的理由是什么。棒极了!非常感谢。我认为Object.Equals和Object.GetHashCode都很好;可继承类的任何比较方法通常都必须是虚拟的,派生类的实现必须对其操作数进行类型检查和类型转换,因此为什么不为相等性测试提供一个标准化的“修补点”?至于MemberwiseClone,将其作为受保护的方法是正确的