简体   繁体   English

对于C#中的原语,==和Equals()之间有什么区别?

[英]What is the difference between == and Equals() for primitives in C#?

Consider this code: 考虑以下代码:

int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge);  //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();

Both int and short are primitive types, but a comparison with == returns true and a comparison with Equals returns false. intshort都是原始类型,但与==的比较返回true,与Equals的比较返回false。

Why? 为什么?

Short answer: 简短回答:

Equality is complicated. 平等很复杂。

Detailed answer: 详细解答:

Primitives types override the base object.Equals(object) and return true if the boxed object is of the same type and value. 基元类型覆盖基础object.Equals(object) ,如果框object类型和值相同,则返回true。 (Note that it will also work for nullable types; non-null nullable types always box to an instance of the underlying type.) (请注意,它也适用于可空类型;非null可空类型总是用于基础类型的实例。)

Since newAge is a short , its Equals(object) method only returns true if you pass a boxed short with the same value. 由于newAgeshort ,因此如果传递具有相同值的盒装short ,则其Equals(object)方法仅返回true。 You're passing a boxed int , so it returns false. 你正在传递一个盒装的int ,所以它返回false。

By contrast, the == operator is defined as taking two int s (or short s or long s). 相比之下, ==运算符被定义为采用两个int (或short s或long s)。
When you call it with an int and a short , the compiler will implicitly convert the short to int and compare the resulting int s by value. 当您使用intshort调用它时,编译器将隐式地将short转换为int并将得到的int与值进行比较。

Other ways to make it work 其他使其工作的方法

Primitive types also have their own Equals() method that accepts the same type. 原始类型也有自己的Equals()方法,它接受相同的类型。
If you write age.Equals(newAge) , the compiler will select int.Equals(int) as the best overload and implicitly convert short to int . 如果编写age.Equals(newAge) ,编译器将选择int.Equals(int)作为最佳重载并隐式将short转换为int It will then return true , since this method simply compares the int s directly. 然后它将返回true ,因为此方法只是直接比较int

short also has a short.Equals(short) method, but int cannot be implicitly converted to short , so you aren't calling it. short也有short.Equals(short)方法,但int不能隐式转换为short ,所以你不是在调用它。

You could force it to call this method with a cast: 您可以强制它使用强制转换来调用此方法:

Console.WriteLine(newAge.Equals((short)age)); // true

This will call short.Equals(short) directly, without boxing. 这将直接调用short.Equals(short) ,而不用拳击。 If age is larger than 32767, it will throw an overflow exception. 如果age大于32767,则会抛出溢出异常。

You could also call the short.Equals(object) overload, but explicitly pass a boxed object so that it gets the same type: 您还可以调用short.Equals(object)重载,但显式传递一个盒装对象,以便它获得相同的类型:

Console.WriteLine(newAge.Equals((object)(short)age)); // true

Like the previous alternative, this will throw an overflow if it doesn't fit in a short . 与之前的替代方案一样,如果它不适合short ,则会抛出溢出。 Unlike the previous solution, it will box the short into an object, wasting time and memory. 与之前的解决方案不同,它会将short成一个物体,浪费时间和记忆。

Source Code: 源代码:

Here are both Equals() methods from the actual source code: 以下是来自实际源代码的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;
    }

Further Reading: 进一步阅读:

See Eric Lippert . Eric Lippert

Because there is no overload for short.Equals that accepts an int . 因为short.Equals接受int是没有重载的。 Therefore, this is called: 因此,这被称为:

public override bool Equals(object obj)
{
    return obj is short && this == (short)obj;
}

obj is not a short .. therefore, it is false. obj short ......因此,它是假的。

For value types, .Equals requires the two objects to be of the same type and have the same value, while == just tests if the two values are the same. 对于值类型, .Equals要求两个对象具有相同的类型并具有相同的值,而==只测试两个值是否相同。

Object.Equals
http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx

When you pass int to short 's Equals you pass object : 当您将int传递给short的Equals时,您传递object

在此输入图像描述 So this pseudocode runs: 所以这个伪代码运行:

return obj is short && this == (short)obj;

== is used for checking a equal condition, it can be considered as an operator(boolean operator), just to compare 2 things and here the data type doesn't matter as there would be a type casting done and Equals is also used for checking equals condition, but in this case the data types should be same. ==用于检查一个相等的条件,它可以被认为是一个运算符(布尔运算符),只是为了比较2个东西,这里数据类型无关紧要,因为会进行类型转换,而Equals也用于检查等于条件,但在这种情况下,数据类型应该相同。 N Equals is a method not an operator. N Equals是一种非操作者的方法。

Below is a small example taken from the one you provided and this will clarify difference in brief,. 以下是您提供的一个小例子,这将简要说明不同之处。

int x=1;
short y=1;
x==y;//true
y.Equals(x);//false

in the above example, X and Y have same values ie 1, and when we use == , it will return true, as in case of == , the short type is converted to int by the compiler and the result is given. 在上面的例子中,X和Y具有相同的值,即1,当我们使用== ,它将返回true,如在==情况下,编译器将short类型转换为int并给出结果。

and when we use Equals , the comparing is done, but the type casting is not done by compiler, so false is returned. 当我们使用Equals ,比较完成,但类型转换不是由编译器完成的,因此返回false。

Guys, please let me know if I'm wrong. 伙计们,如果我错了,请告诉我。

In many contexts where a method or operator argument is not of the required type, the C# compiler will attempt to perform an implicit type conversion. 在方法或运算符参数不是所需类型的许多上下文中,C#编译器将尝试执行隐式类型转换。 If the compiler can make all arguments satisfy their operators and methods by adding implicit conversions, it will do so without complaint, even though in some cases (especially with equality tests!) the results may be surprising. 如果编译器可以通过添加隐式转换使所有参数满足其运算符和方法,那么即使在某些情况下(特别是使用相等测试!),结果可能会令人惊讶。

Further, each value type such as int or short actually describes both a kind of value and a kind of object(*). 此外,诸如intshort每个值类型实际上描述了一种值和一种对象(*)。 Implicit conversions exist to convert values to other kinds of values, and to convert any kind of value to its corresponding kind of object, but the different kinds of objects are not implicitly convertible to each other. 隐式转换的存在是为了将值转换为其他类型的值,并将任何类型的值转换为其对应的对象类型,但不同类型的对象不能隐式地相互转换。

If one uses the == operator to compare a short and an int , the short will be implicitly converted to an int . 如果使用==运算符来比较shortint ,则short将被隐式转换为int If its numerical value was equal to that of the int , the int to which it was converted will equal the int to which it is compared. 如果其数值是等于的int时, int到它被转换将等于int到其所比较。 If one attempts to use the Equals method on the short to compare it with an int , however, the only implicit conversion which would satisfy an overload of the Equals method would be the conversion to the object type corresponding to int . 但是,如果尝试在short上使用Equals方法将其与int进行比较,那么满足Equals方法重载的唯一隐式转换就是转换为int对应的对象类型。 When the short is asked whether it matches the passed-in object, it will observe that the object in question is an int rather than a short and thus conclude that it cannot possibly be equal. 当询问short是否与传入的对象匹配时,它将观察到所讨论的对象是int而不是short ,因此得出结论它不可能是相等的。

In general, although the compiler won't complain about it, one should avoid comparing things which are not of the same type; 一般来说,虽然编译器不会抱怨它,但应该避免比较不同类型的东西; if one is interested in whether conversion of things to a common form would give the same result, one should perform such conversion explicitly. 如果人们对将事物转换为共同形式是否会产生相同结果感兴趣,则应明确执行此类转换。 Consider, for example, 例如,考虑一下

int i = 16777217;
float f = 16777216.0f;

Console.WriteLine("{0}", i==f);

There are three ways in which one might want to compare an int to a float . 有三种方法可以将intfloat进行比较。 One might want to know: 有人可能想知道:

  1. Does the closest possible float value to the int match the float ? 是否可能最接近的float值的int匹配float
  2. Does the whole-number part of the float match the int ? floatint部分是否与int匹配?
  3. Do the int and float represent the same numerical value. intfloat表示相同的数值。

If one tries to compare an int and float directly, the compiled code will answer the first question; 如果试图直接比较intfloat ,编译后的代码将回答第一个问题; whether that's what the programmer intended, however, will be far from obvious. 然而,程序员的意图是否远非显而易见。 Changing the comparison to (float)i == f would make it clear that the first meaning was intended, or (double)i == (double)f would cause the code to answer the third question (and make it clear that's what was intended). 将比较更改为(float)i == f会清楚地表明第一个含义是预期的,或者(double)i == (double)f会导致代码回答第三个问题(并清楚地说明是什么是意)。

(*) Even if the C# spec regards a value of type eg System.Int32 as being an object of type System.Int32 , such a view is contradicted by the requirement that a code run on a platform whose spec regards values and objects as inhabiting different universes. (*)即使C#规范关于类型例如值System.Int32为类型的一个目的System.Int32 ,这样的视图被作为栖息其规格对于值和对象平台上的代码运行的要求相矛盾不同的宇宙。 Further, if T is a reference type, and x is a T , then a reference of type T should be able to refer to x . 此外,如果T是引用类型,并且xT ,则类型T的引用应该能够引用x Thus, if a variable v of type Int32 holds an Object , a reference of type Object should be able to hold a reference to v or its contents. 因此,如果Int32类型的变量v包含Object ,则Object类型的引用应该能够保存对v或其内容的引用。 In fact, a reference of type Object would be able to point to an object holding data copied from v , but not to v itself nor to its contents. 事实上, Object类型的引用将能够指向一个包含从v复制的数据的对象,但不能指向v本身或其内容。 That would suggest that neither v nor its contents is really an Object . 这表明v及其内容都不是真正的Object

Equals() is a method of System.Object Class Equals()System.Object类的方法
Syntax : Public virtual bool Equals() 语法: Public virtual bool Equals()
Recommendation if we want to compare state of two objects then we should use Equals() method 建议如果我们想要比较两个对象的状态,那么我们应该使用Equals()方法

as stated above answers == operators compare the values are same. 如上所述答案==运算符比较值相同。

Please don't get confused with ReferenceEqual 请不要与ReferenceEqual混淆

Reference Equals() 参考等号()
Syntax : public static bool ReferenceEquals() 语法:public static bool ReferenceEquals()
It determine whether the specified objects instance are of the same instance 它确定指定的对象实例是否属于同一实例

What you need to realize is that doing == will always end up calling a method. 你需要意识到的是,做==总是会调用一个方法。 The question is whether calling == and Equals ends up calling/doing the same things. 问题是调用==Equals是否最终调用/执行相同的操作。

With reference types, == will always 1st check whether the references are the same ( Object.ReferenceEquals ). 对于引用类型, ==将始终首先检查引用是否相同( Object.ReferenceEquals )。 Equals on the other hand can be overridden and may check whether some values are equal. 另一方面, Equals可以被覆盖并且可以检查某些值是否相等。

EDIT: to answer svick and add on SLaks comment, here is some IL code 编辑:回答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.

== In Primitive ==在原始

Console.WriteLine(age == newAge);          // true

In primitive comparison == operator behave quite obvious, In C# there are many == operator overload available. 在原始比较中==运算符表现得非常明显,在C#中有许多==运算符重载可用。

  • string == string string == string
  • int == int int == int
  • uint == uint uint == uint
  • long == long 长==长
  • many more 还有很多

So in this case there is no implicit conversion from int to short but short to int is possible. 因此,在这种情况下,有从没有隐式转换intshort ,但shortint是可能的。 So newAge is converted into int and comparison occurs which returns true as both holds same value. 因此newAge被转换为int并且发生比较,返回true,因为两者都保持相同的值。 So it is equivalent to: 所以它相当于:

Console.WriteLine(age == (int)newAge);          // true

.Equals() in Primitive .Equals()in Primitive

Console.WriteLine(newAge.Equals(age));         //false

Here we need to see what Equals() method is, we calling Equals with a short type variable. 这里我们需要看看Equals()方法是什么,我们用一个短类型变量调用Equals。 So there are three possibilities: 所以有三种可能性:

  • Equals(object, object) // static method from object 等于(对象,对象)//来自对象的静态方法
  • Equals(object) // virtual method from object Equals(object)//来自对象的虚方法
  • Equals(short) // Implements IEquatable.Equals(short) Equals(short)//实现IEquatable.Equals(简短)

First type is not case here as number of arguments are different we calling with only one argument of type int. 第一种类型不是这里的情况,因为参数的数量不同,我们只用一个int类型的参数调用。 Third is also eliminated as mentioned above implicit conversion of int to short is not possible. 如上所述,第三个也被消除了隐含的int转换为short是不可能的。 So here Second type of Equals(object) is called. 所以这里调用第二种类型的Equals(object) The short.Equals(object) is: short.Equals(object)是:

bool Equals(object z)
{
  return z is short && (short)z == this;
}

So here condition got tested z is short which is false as z is an int so it returns false. 所以这里条件得到测试z is short ,这是假的,因为z是一个int所以它返回false。

Here is detailed article from Eric Lippert 以下是Eric Lippert的详细文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM