==和Equals()在C#中的基元有什么区别?
考虑这个代码:
int age = 25; short newAge = 25; Console.WriteLine(age == newAge); //true Console.WriteLine(newAge.Equals(age)); //false Console.ReadLine();
int
和short
都是原始types,但与==
的比较返回true,与Equals
的比较返回false。
为什么?
简短的回答:
平等是复杂的。
详细答案:
基本types重写基础object.Equals(object)
,如果装箱的object
具有相同的types和值,则返回true。 (请注意,它也适用于可为空的types;非null的可空types总是框到基础types的实例。
由于newAge
是short
,所以如果你传递一个带有相同值的盒装short ,它的Equals(object)
方法只返回true。 你传递一个盒装的int
,所以它返回false。
相比之下, ==
运算符被定义为接受两个int
(或者short
s或long
s)。
当你用一个int
和short
调用它时,编译器会隐式地把short
转换成int
然后用值来比较结果的int
。
其他方法来使其工作
原始types也有自己的Equals()
方法,接受相同的types。
如果你写age.Equals(newAge)
,编译器将selectint.Equals(int)
作为最好的重载并隐式地将short
转换为int
。 然后它会返回true
,因为这个方法直接比较int
。
short
也有一个short.Equals(short)
方法,但int
不能被隐式转换为short
,所以你不会调用它。
你可以强制它用cast来调用这个方法:
Console.WriteLine(newAge.Equals((short)age)); // true
这将称为short.Equals(short)
直接,没有拳击。 如果age
大于32767,则会引发溢出exception。
您也可以调用short.Equals(object)
重载,但显式传递一个装箱对象,以便获得相同的types:
Console.WriteLine(newAge.Equals((object)(short)age)); // true
就像之前的select一样,如果不适合做short
话,这将会导致溢出。 与以前的解决scheme不同的是,它将short
变成了一个对象,浪费了时间和内存。
源代码:
这里是来自实际源代码的两个Equals()
方法:
public override bool Equals(Object obj) { if (!(obj is Int16)) { return false; } return m_value == ((Int16)obj).m_value; } public bool Equals(Int16 obj) { return m_value == obj; }
进一步阅读:
见Eric Lippert 。
因为short.Equals
没有超载。接受int
short.Equals
。 因此,这被称为:
public override bool Equals(object obj) { return obj is short && this == (short)obj; }
obj
不是short
..因此,这是错误的。
对于值types, .Equals
需要两个对象是相同的types,并具有相同的值,而==
只是testing两个值是否相同。
Object.Equals
http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx
当你将int
传递给short
,Equals传递object
:
所以这个伪码运行:
return obj is short && this == (short)obj;
==
用于检查一个相等的条件,它可以被认为是一个运算符(布尔运算符),只是比较两件事情,这里的数据types并不重要,因为会有一个types转换完成, Equals
也用于检查等于条件,但在这种情况下,数据types应该是相同的。 N等于是一种不是操作员的方法。
下面是一个从你提供的一个小例子,这将澄清在简要的差异。
int x=1; short y=1; x==y;//true y.Equals(x);//false
在上面的例子中,X和Y有相同的值,即1,当我们使用==
,它将返回true,如==
情况下,shorttypes被编译器转换为int并给出结果。
当我们使用Equals
,比较完成了,但是types转换不是由编译器完成的,所以返回false。
伙计们,请让我知道,如果我错了。
Equals()是System.Object类的一个方法
语法: 公共虚拟BOOL Equals()
build议如果我们想比较两个对象的状态,那么我们应该使用Equals()方法
如上所述,答案==运算符的值相同。
请不要与ReferenceEqual混淆
参考平等()
语法:public static bool ReferenceEquals()
它确定指定的对象实例是否具有相同的实例
在许多方法或运算符参数不是所需types的上下文中,C#编译器将尝试执行隐式types转换。 如果编译器可以通过添加隐式转换使所有参数满足其操作符和方法,那么即使在某些情况下(特别是在进行相等性testing时),结果也可能会令人惊讶。
此外, int
或short
等每个值types实际上都描述了一种值和一种对象(*)。 存在隐式转换来将值转换为其他types的值,并将任何types的值转换为其相应的对象types,但是不同种类的对象不能隐式地相互转换。
如果使用==
运算符来比较short
和int
,则short
将被隐式转换为int
。 如果它的数值等于int
数值,则它所转换的int
将等于它所比较的int
。 如果试图使用短方法上的Equals
方法与int
进行比较,那么只有满足Equals
方法重载的唯一隐式转换才是对应于int
的对象types的转换。 当询问short
是否与传入的对象相匹配时,它会观察到所讨论的对象是一个int
而不是short
,从而得出结论:它不可能是相等的。
一般来说,虽然编译器不会抱怨,但是应该避免比较不同types的东西; 如果一个人对是否将事物转换成一个通用的forms会产生相同的结果感兴趣,那么应该明确地进行这种转换。 考虑一下,例如,
int i = 16777217; float f = 16777216.0f; Console.WriteLine("{0}", i==f);
有三种方法可以将一个int
与一个float
进行比较。 有人可能想知道:
- 是否最接近可能的
float
值与int
匹配? -
float
的int
部分是否与int
匹配? -
int
和float
表示相同的数值。
如果试图直接比较int
和float
,编译后的代码将回答第一个问题; 不pipe程序员的意图是什么,但是远不是那么明显。 改变比较为(float)i == f
会清楚地表明,第一个意思是打算,或(double)i == (double)f
将导致代码回答第三个问题(并明确这就是意)。
(*)即使C#规范将types的值(例如System.Int32
视为System.Int32
types的对象,这样的视图也会违反代码在规范将值和对象视为居住的平台上运行的要求不同的宇宙。 此外,如果T
是一个引用types,并且x
是一个T
,那么typesT
的引用应该能够引用x
。 因此,如果一个Int32
types的variablesv
持有一个Object
,那么Object
types的引用应该能够保存对v
或其内容的引用。 事实上, Object
types的引用将能够指向一个对象,该对象持有从v
复制的数据,但不是v
本身或其内容。 这表明, v
和它的内容都不是真的是一个Object
。
你需要认识到的是做==
总是会调用一个方法。 问题是调用==
和Equals
是否最终调用/执行相同的操作。
对于引用types, ==
总是会首先检查引用是否相同( Object.ReferenceEquals
)。 另一方面, Equals
可以被覆盖,并且可以检查一些值是否相等。
编辑:回答svick并添加SLaks评论,这里是一些IL代码
int i1 = 0x22; // ldc.i4.s ie pushes an int32 on the stack int i2 = 0x33; // ldc.i4.s short s1 = 0x11; // ldc.i4.s (same as for int32) short s2 = 0x22; // ldc.i4.s s1 == i1 // ceq i1 == s1 // ceq i1 == i2 // ceq s1 == s2 // ceq // no difference between int and short for those 4 cases, // anyway the shorts are pushed as integers. i1.Equals(i2) // calls System.Int32.Equals s1.Equals(s2) // calls System.Int16.Equals i1.Equals(s1) // calls System.Int32.Equals: s1 is considered as an integer // - again it was pushed as such on the stack) s1.Equals(i1) // boxes the int32 then calls System.Int16.Equals // - int16 has 2 Equals methods: one for in16 and one for Object. // Casting an int32 into an int16 is not safe, so the Object overload // must be used instead.
==在原始
Console.WriteLine(age == newAge); // true
在原始比较==运算符行为相当明显,在C#中有很多==运算符超载可用。
- string==string
- int == int
- uint == uint
- 长==长
- 还有很多
所以在这种情况下,不存在从int
到int
隐式转换,但是可能会short
到int
。 所以newAge被转换为int,并且比较发生,因为两者都保持相同的值,所以返回true。 所以它相当于:
Console.WriteLine(age == (int)newAge); // true
.Equals()in Primitive
Console.WriteLine(newAge.Equals(age)); //false
这里我们需要看看Equals()方法是什么,我们用一个简短的typesvariables来调用Equals。 所以有三种可能性:
- 等于(对象,对象)//从对象的静态方法
- 等于(object)//从对象的虚拟方法
- Equals(short)//实现IEquatable.Equals(short)
第一种types不是这种情况,因为参数个数不同,我们只用一个inttypes的参数来调用。 第三也是如上所述淘汰int的简短转换是不可能的。 所以这里调用第二类Equals(object)
。 这个short.Equals(object)
是:
bool Equals(object z) { return z is short && (short)z == this; }
所以这里条件得到了testingz is short
这是错误的,因为z是一个int,所以它返回false。
这里是来自Eric Lippert的详细文章