请考虑以下代码:
int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge); //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();
无论是 int
还是 short
,它们都是原始类型,但使用 ==
进行比较返回 true,而使用 Equals
进行比较返回 false。
为什么呢?
平等是复杂的。
基元类型重写了基本的object.Equals(object)
方法,并且如果装箱后的object
与相同的类型和值,则返回true。(请注意,对于可空类型也适用;非null可空类型始终装箱为基础类型的实例。)
由于newAge
是一个short
,因此它的Equals(object)
方法仅在传递具有相同值的装箱short
时返回true。您正在传递一个装箱的int
,因此它返回false。
相比之下,==
运算符被定义为接受两个int
(或short
或long
)。
当您使用一个int
和一个short
调用它时,编译器将隐式地将short
转换为int
,并按值比较结果为int
的两个数。
基元类型还有自己的Equals()
方法,接受相同的类型。
如果您编写age.Equals(newAge)
,编译器将选择int.Equals(int)
作为最佳重载,并隐式地将short
转换为int
。然后它将返回true
,因为此方法直接比较int
。
short
还有一个short.Equals(short)
方法,但int
无法隐式转换为short
,因此不会调用它。
您可以使用强制转换来强制调用此方法:
Console.WriteLine(newAge.Equals((short)age)); // true
这将直接调用 short.Equals(short)
,而不需要装箱。如果 age
大于32767,它将抛出溢出异常。
您还可以调用 short.Equals(object)
重载,但明确传递一个装箱对象以使其获得相同的类型:
Console.WriteLine(newAge.Equals((object)(short)age)); // true
和之前的替代方法一样,如果它不能适应short
,这个方法会抛出溢出。
与之前的解决方案不同的是,它将 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的文章。
long
等同于 int
,那么 int
会被隐式转换为 long
,对吗? - Selman Genç==
运算符通过引用比较引用类型。对于值类型和重载 ==
的类型,它不会这样做。 - SLaksint
不能转换为short
。相反,它调用Equals(object)
,在调用点隐式装箱。请仔细阅读我的答案。 - SLaks因为没有接受 int
的 short.Equals
这个重载方法。因此,这被称为:
public override bool Equals(object obj)
{
return obj is short && this == (short)obj;
}
obj
不是一个short
类型,因此是假的。
对于值类型而言,.Equals
要求这两个对象具有相同的类型和相同的值,而 ==
只是测试这两个值是否相同。
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;
==
用于检查相等条件,它可以被视为运算符(布尔运算符),只是比较两个东西,这里数据类型并不重要,因为会进行类型转换。而Equals
也用于检查相等条件,但在这种情况下,数据类型应该相同。N Equals 是一个方法而不是运算符。
以下是从您提供的示例中摘取的一个小示例,这将简要解释差异。
int x=1;
short y=1;
x==y;//true
y.Equals(x);//false
在上面的例子中,X和Y具有相同的值,即1,当我们使用==
时,编译器将short类型转换为int类型并给出结果,因此它将返回true。而当我们使用Equals
时,进行比较,但编译器不执行类型转换,因此会返回false。请各位指正。Equals()是System.Object类的一个方法
语法:Public virtual bool Equals()
建议如果我们想要比较两个对象的状态,则应使用Equals()方法
如上所述,==操作符比较的值是否相同。
请不要与ReferenceEqual混淆
Reference Equals()
语法:public static bool ReferenceEquals()
它确定指定的对象实例是否是相同的实例
int i = 16777217;
float f = 16777216.0f;
Console.WriteLine("{0}", i==f);
bool SelfSame<T>(T p) { return Object.ReferenceEquals((Object)p,(Object)p);}
。值类型对应的装箱对象类型可以通过保持标识的向上转换满足ReferenceEquals
的参数类型;然而,存储位置类型需要进行非标识保持的转换。如果将T
强制转换为U
会产生指向原始T
以外的引用,则这表明T
实际上不是U
。 - supercatT
?据我所知,C++/CLI使用语法表示"boxed int"为int^
,对于那些有一些自定义标记的ValueType
或Object
进行表示,如果您实际上可以使用它们,这可能有点奇怪。 - CodesInChaosSystem.Int32
这样的类型用于描述存储位置时,它标识了存储位置的类型。当它用于描述堆对象时,它标识了堆对象的类型。CLR没有提供定义引用类型存储位置的方法,该存储位置仅限于保存对类型为Int32
的堆对象的引用。 - supercat==
操作总是会调用一个方法。问题在于调用==
和Equals
是否最终会调用/执行相同的内容。==
操作首先会检查引用是否相同(Object.ReferenceEquals
)。而Equals
可以被重写并且可能会检查某些值是否相等。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.
==
并不是魔法,它最终只是调用一个方法(大多数程序员可能从未实现/覆盖任何运算符)是很有趣的。也许我本可以在你的问题中添加评论,而不是添加自己的答案。如果你认为我说的有意义,请随意更新你的答案。 - user276648== 原始模式
Console.WriteLine(age == newAge); // true
在原始的比较中,==运算符的行为非常明显,在C#中有许多==运算符重载可用。
因此,在这种情况下,从int
到short
没有隐式转换,但是short
到int
是可以的。所以newAge被转换为int并进行比较,返回true,因为两者具有相同的值。因此,它等效于:
Console.WriteLine(age == (int)newAge); // true
.Equals() 在原始类型中的应用
Console.WriteLine(newAge.Equals(age)); //false
Equals(object)
。 short.Equals(object)
是:bool Equals(object z)
{
return z is short && (short)z == this;
}
所以这里测试了条件z is short
,但由于z是int类型,因此返回false。
Console.WriteLine(age.Equals(newAge));
- ANevesEquals()
一般的内容。 - SLaks