【问题标题】:Why object.Equals and instanceobject.Equals are not same为什么 object.Equals 和 instanceobject.Equals 不一样
【发布时间】:2012-04-03 13:43:24
【问题描述】:
        string s1 = "t";
        string s2 = 't'.ToString();        

        Console.WriteLine(s1.Equals(s2)); // returning true
        Console.WriteLine(object.Equals(s1, s2)); // returning true

这里返回相同的结果。现在,当我使用 StringBuilder 时,它不会返回相同的值。背后的原因是什么?

        StringBuilder s1 = new StringBuilder();
        StringBuilder s2 = new StringBuilder();

        Console.WriteLine(s1.Equals(s2)); // returning true
        Console.WriteLine(object.Equals(s1, s2)); // returning false

Edit1:我上面的问题在下面回答。但是在这次讨论中,我们发现 StringBuilder 在其实现中没有任何覆盖 Equals 方法。因此,当我们调用 StringBuilder.Equals 时,它实际上转到了 Object.Equals。因此,如果有人调用 StringBuilder.Equals 和 S1.Equals(S2) 结果会有所不同。

【问题讨论】:

  • 好收获!底线,StringBuilder 似乎忘记覆盖Equals(object)。让Equals(StringBuilder)Equals(object) 具有不同的行为似乎违反直觉。

标签: c# string stringbuilder


【解决方案1】:

generic Equals method 比较两个对象的引用,以查看它们对于引用类型(例如 StringBuilder)是否具有 reference 相等性。对于值类型,string 的行为类似于值类型(不可变),它会进行按位比较(确定二进制表示是否相同)。但是,此功能在 StringBuilder 类中被重载。

根据MSDN,如果两个StringBuilder对象的以下条件相等,则StringBuilder的equal方法将返回true:

  • 字符串
  • 容量
  • 最大容量

因此,第二个示例中的 s1 和 s2 引用相等性失败,但根据刚才提到的条件通过自定义 StringBuilder Equals 相等性。

【讨论】:

  • 字符串不是值类型。 (它是一种具有值语义的引用类型。)stackoverflow.com/questions/1069155/…
  • @BradleyGrainger,我知道从技术上讲它不是值类型,但在这种情况下它的作用相同。我会更新我的答案以澄清。谢谢。
【解决方案2】:

String.Equals() 在 C# 中被覆盖,因此当使用在 string 上定义的 Equal() 覆盖时,相同的字符串实际上是 Equal()

如果您正在比较 string literals(在您的示例中不是这种情况),值得注意的是相同的字符串文字是 interned... 也就是说,相同的字符串位于相同的地址,因此通过引用也将相等(例如 object.Equals() 或 s1.ReferenceEquals(s2))以及按值。

StringBuilder 为Equals() 提供了一个重载,它将StringBuilder 作为参数(即s1.Equals(s2) 将调用该重载而不是调用object.Equals(object obj))。

http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.equals.aspx

StringBuilder.Equals() 是...

如果此实例和 sb 具有相等的字符串、Capacity 和 最大容量值;否则为假。

object.Equals() 使用static Equals() defined on object,它只检查引用相等(如果传递一个类)或value equality(如果传递一个结构)。

总结一下

string s1 = "t";
string s2 = 't'.ToString();        

Console.WriteLine(s1.Equals(s2)); // true because both reference equality (interned strings) and value equality (string overrides Equals())
Console.WriteLine(object.Equals(s1, s2)); // true because of reference equality (interned strings)

StringBuilder s1 = new StringBuilder();
StringBuilder s2 = new StringBuilder();

Console.WriteLine(s1.Equals(s2)); // true because StringBuilder.Equals() overloaded
Console.WriteLine(object.Equals(s1, s2)); // false because the two StringBuilder instances have different addresses (references not equal)

【讨论】:

  • 从技术上讲,StringBuilder 只会重载 Equals 方法,而不会覆盖虚拟 object.Equals(object)。这就是为什么两种方法表现不同的原因。我想知道他们是否忘记在 NET1.0 中这样做并且不想引入重大更改?
  • @alexm:很好。我以前没有注意到这一点。更新了我的答案。
  • 感谢 Eric 的精彩解释。如果我从中做一个小总结: object.Equals 将根据输入对象类型检查引用或值。而 String 和 StringBuilder 有它们自己的重载/重写的 Equal 方法,可以根据它们的实现工作。如果我错了,请纠正我。
  • 我还更新了 2 个 stringbuilder 声明为 - StringBuilder s1 = new StringBuilder("abc", 10); StringBuilder s2 = new StringBuilder("abc", 10);那么为什么下面2个实例返回不同的值 Console.WriteLine(s1.Equals(s2)); // true Console.WriteLine(StringBuilder.Equals(s1, s2)); // false 提前谢谢
  • 默认情况下,相同的字符串是not;这很容易用以下代码证明:object.ReferenceEquals(new StringBuilder("abc").ToString(), new StringBuilder("abc").ToString())(返回 false)。请注意,C# 程序中相同的字符串文字将引用相同的对象。 “当根据字符串相等运算符(第 7.9.7 节)等效的两个或多个字符串文字出现在同一个程序集中时,这些字符串文字引用同一个字符串实例。” (msdn.microsoft.com/en-us/library/aa691090.aspx)
【解决方案3】:

字符串类以比较字符串值的方式实现 Equals。

大多数对象实例,除非它们实现不同类型的比较,否则检查对象引用是否相同。

请注意,还有一种情况是,两个包含完全相同值的不同字符串常量最初被编译器分配给同一个对象引用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多