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 }
任何理由为什么发生这种情况?
当在object
types的expression式上使用==
,它将parsing为System.Object.ReferenceEquals
。
Equals
只是一个virtual
方法和行为,所以重写的版本将被使用(其中,为string
types比较内容)。
在比较对象引用和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。
据我所知,答案很简单:
- ==比较对象引用。
- .Equals比较对象内容。
- 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”中的字符