C#与==和Equals()之间的区别

我有一个Silverlight应用程序的条件比较2个string,出于某种原因,当我使用==它返回false.Equals()返回true

这里是代码:

 if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack")) { // Execute code } if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack") { // Execute code } 

任何理由为什么发生这种情况?

当在objecttypes的expression式上使用== ,它将parsing为System.Object.ReferenceEquals

Equals只是一个virtual方法和行为,所以重写的版本将被使用(其中,为stringtypes比较内容)。

在比较对象引用和string(即使对象引用引用string)时,特定于string类的==运算符的特殊行为将被忽略。

通常(不处理string时), Equals比较 ,而==比较对象引用 。 如果你正在比较的两个对象是指同一个对象的确切实例,那么两者都将返回true,但是如果一个具有相同的内容并且来自不同的源(是具有相同数据的单独实例),则只有Equals会返回true。 但是,正如注释中所指出的那样,string是一个特殊情况,因为它重写了==运算符,因此当纯粹处理string引用(而不是对象引用)时,即使它们是单独的实例,也只会比较这些值。 以下代码说明了行为中的细微差别:

 string s1 = "test"; string s2 = "test"; string s3 = "test1".Substring(0, 4); object s4 = s3; Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4)); 

输出是:

 True True True False True True False False True 

==.Equals都取决于实际types中定义的行为和呼叫站点的实际types。 两者都只是方法/操作符,可以在任何types上重写,并赋予作者所期望的任何行为。 根据我的经验,我发现人们.Equals在对象上实现.Equals ,而忽略实现operator == 。 这意味着.Equals实际上会测量值的相等,而==会衡量它们是否是相同的参考。

当我正在使用定义不确定的新types或编写通用algorithm时,我发现最佳实践如下

  • 如果我想比较C#中的引用,我直接使用Object.ReferenceEquals (通用情况下不需要)
  • 如果我想比较值,我使用EqualityComparer<T>.Default

在某些情况下,当我感觉==的用法不明确时,我将在代码中明确使用Object.Reference equals来消除歧义。

Eric Lippert最近做了一篇关于为什么CLR中有两种平等方法的博客文章。 这是值得的阅读

首先,有一个区别。 数字

 > 2 == 2.0 True > 2.Equals(2.0) False 

而对于string

 > string x = null; > x == null True > x.Equals(null) NullReferenceException 

在这两种情况下, ==.Equals

我会补充说,如果你把你的对象的string,那么它会正常工作。 这就是为什么编译器会给你一个警告,说:“可能意外的引用比较;获得一个值比较,左侧input'string'”

==运算符 1.如果操作数是值types,并且它们的值相等,则返回true否则返回false。 2.如果操作数是除了string的引用types ,并且都指向同一个对象,则返回true否则返回false。 3.如果操作数是stringtypes,并且它们的值相等,则返回true否则返回false。

.Equals 1.如果操作数是引用types,则它执行引用相等 ,即如果两个引用相同的对象,则返回true否则返回false。 2.如果操作数是值types,那么与==运算符不同,它首先检查它们的types,如果它们的types相同,则执行==运算符,否则返回false。

据我所知,答案很简单:

  1. ==比较对象引用。
  2. .Equals比较对象内容。
  3. string数据types总是像内容比较一样。

我希望我是正确的,它回答了你的问题。

我在这里有点困惑。 如果Content的运行时types是stringtypes,那么==和Equals都应该返回true。 然而,由于看起来不是这种情况,所以运行时types的内容不是string,调用Equals就是在做一个引用的平等,这就解释了Equals(“Energy Attack”)失败的原因。 但是,在第二种情况下,应该调用哪个重载==静态运算符的决定是在编译时做出的,并且这个决定看起来是==(string,string)。 这表明内容提供了一个隐式转换为string。

@BlueMonkMN还有一个更早的答案。 另外一个维度是,对于Drahcir标题问题的回答,也取决于我们如何得到string值。 为了显示:

 string s1 = "test"; string s2 = "test"; string s3 = "test1".Substring(0, 4); object s4 = s3; string s5 = "te" + "st"; object s6 = s5; Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2)); Console.WriteLine("\n Case1 - A method changes the value:"); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4)); Console.WriteLine("\n Case2 - Having only literals allows to arrive at a literal:"); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5)); Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6)); 

输出是:

 True True True Case1 - A method changes the value: False True True False False True Case2 - Having only literals allows to arrive at a literal: True True True True True True 

给答案增加一点。

.EqualsTo()方法使您能够与文化和区分大小写进行比较。

C#中的==标记用于两个不同的相等检查运算符。 当编译器遇到该令牌时,它将检查被比较的任何一种types是否为所比较的特定组合types(*)或者可以转换两种types的组合types实现了相等运算符重载。 如果编译器发现这样的超载,它将使用它。 否则,如果两种types都是引用types,并且它们不是不相关的类(可以是接口,也可以是相关的类),编译器会将==作为引用比较运算符。 如果两个条件都不适用,编译将失败。

请注意,其他一些语言对两个相等检查运算符使用不同的标记。 例如,在VB.NET中, =expression式在expression式中仅用于可重载的等式检查运算符,而Is用作引用testing或空testing运算符。 对于不覆盖等号检查运算符的types使用=将会失败,因为除了testing引用相等或无效以外,将尝试使用Is用于任何目的。

(*)types通常只有与自身进行比较的过载相等,但对于types来说,重载相等运算符以便与其他特定types进行比较可能是有用的。 例如, int可以(和恕我直言,应该有,但没有)定义一个相等运算符与float比较,以便16777217不会报告自己等于16777216f。 实际上,由于没有定义这样的运算符,因此C#会将int提升为float ,在equal-check运算符看到它之前将其四舍五入为16777216f; 那么操作员就会看到两个相同的浮点数,并将它们报告为相等,而不知道发生的四舍五入。

真的很棒的答案和例子!

我只想补充两者之间的根本区别,

==这样的运算符不是多态的, Equals

有了这个概念,如果你找出任何例子(通过查看左手和右手的引用types,并检查/知道types是否实际上==运算符重载和等于被覆盖),你一定会得到正确的答案。

当我们创build任何对象时,对象有两个部分,一个是内容,另一个是对该内容的引用。 ==比较内容和参考; equals()仅比较内容

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq

Equal和==之间的唯一区别在于对象types比较。 在其他情况下,如引用types和值types,它们几乎是相同的(无论是按位平等还是两者都是引用相等)。

对象:等于:按位平等==:引用相等

string:(等于和==对于string是一样的,但是如果其中一个string改变为对象,那么比较结果将会不同)等于:按位相等==:按位相等

在这里看到更多的解释。

==

==运算符可以用来比较任何types的两个variables, 它只是比较比特

 int a = 3; byte b = 3; if (a == b) { // true } 

注意:在int的左边有更多的零,但是我们不关心这个。

int a(00000011)== byte b(00000011)

记住==操作符只关心variables中位的模式。

使用==如果两个引用(primitives)引用堆中的同一个对象。

无论variables是引用还是原语,规则都是相同的。

 Foo a = new Foo(); Foo b = new Foo(); Foo c = a; if (a == b) { // false } if (a == c) { // true } if (b == c) { // false } 

a == c是真的a == b是假的

a和c的位模式是一样的,所以它们使用==相等。

等于():

使用equals()方法来查看两个不同的对象是否相等

比如两个不同的String对象都表示“Jane”中的字符