简体   繁体   English

比较C#对象

[英]Comparing C# object

Consider this code: 考虑以下代码:

object str1 = "shahrooz";
object str2 = "shahrooz";
object int1 = 1;
object int2 = 1;

Console.WriteLine("str1 == str2 : " + (str1 == str2));
Console.WriteLine("int1 == int2 : " + (int1 == int2));
Console.ReadLine();

When you run this code you will get this result: 运行此代码时,将得到以下结果:

str1 == str2 : True
int1 == int2 : False

Both compare are object but why the first comparison returns true but second comparison returns false? 两个比较都是对象,但是为什么第一个比较返回true但第二个比较返回false?

The == operator performs a reference equality check if both operands are of type object or no more specific equality operator can be determined based on the compile-time types of the operands. 如果两个操作数均为object类型,或者不能根据操作数的编译时类型确定更多特定的相等运算符,则==运算符将执行引用相等性检查。

In your case the compile-time operand types are object , so reference equality is checked. 在您的情况下,编译时操作数类型为object ,因此将检查引用相等性。 At the time when you assigned 1 to either variable, the runtime "boxed" the value into an object. 当您为任一变量分配1时,运行时会将值“装箱”到一个对象中。 As a result you get two objects that contain the integer value one, but they are two separate objects, thus reference equality returns false . 结果,您得到两个包含整数值1的对象,但是它们是两个单独的对象,因此引用相等返回false

To perform value equality comparison, use the Equals() method. 要执行值相等比较,请使用Equals()方法。 It can be overridden in subclasses to perform type-specific value comparison, which I believe is what you want to do. 可以在子类中重写它,以执行特定于类型的值比较,我相信这是您想要做的。 The expression int1.Equals(int2) should return what you want. 表达式int1.Equals(int2)应该返回您想要的。 Since both variables are nullable, you might want to write it as int1 != null ? int1.Equals(int2) : int2 == null 由于两个变量都是可为空的,因此您可能希望将其写为int1 != null ? int1.Equals(int2) : int2 == null int1 != null ? int1.Equals(int2) : int2 == null to prevent throwing NullReferenceException when int1 is null . int1 != null ? int1.Equals(int2) : int2 == null以防止在int1nullint1 != null ? int1.Equals(int2) : int2 == null NullReferenceException。

Doing (int1 == int2) compares 2 objects, which are different, due to the CLR's boxing: when you put a ValueType inside a ReferenceType, .NET does boxing for you, so you get 2 different objects, each boxes the 1 value that you assigned. 进行(int1 == int2)比较2个对象(由于CLR的装箱而不同):当将ValueType放入ReferenceType内时,.NET会为您装箱,因此您将获得2个不同的对象,每个对象都装箱1个您分配的。

To make the comparison work, you need to either store the 2 numbers in int s, 要进行比较,您需要将2个数字存储在int中
or do ((int)int1 == (int)int2) 或做((int)int1 == (int)int2)

For info about boxing, see this article: 有关拳击的信息,请参阅本文:
Boxing and Unboxing (C# Programming Guide) 装箱和拆箱(C#编程指南)
https://msdn.microsoft.com/en-us/library/yz2be5wk.aspx https://msdn.microsoft.com/zh-CN/library/yz2be5wk.aspx

A quick and dirty check of memory addressing helps to shine light on this using this (grabbed from here ): 快速而肮脏的内存寻址检查有助于使用以下命令(从此处抓取)来阐明这一点:

public static IntPtr GetAddress(object o)
{
    unsafe
    {
        TypedReference tr = __makeref(o);
        IntPtr ptr = **(IntPtr**)(&tr);
        return ptr;
    }
}

You can then do this: 然后,您可以执行以下操作:

Console.WriteLine(GetAddress(str1));
Console.WriteLine(GetAddress(str2)); 
Console.WriteLine(GetAddress(int1)); 
Console.WriteLine(GetAddress(int2));

I get: 我得到:

35839968
35839968
35840128
35840152

What you should see is that the address of str1 and str2 are identical, and the address of int1 and int2 are different. 您应该看到的是str1str2的地址相同,而int1int2的地址不同。 This is because your strings are interned (because they are string literals ). 这是因为您的字符串是内部字符串(因为它们是字符串文字 )。 A single copy of the string shahrooz is stored in memory and both str1 and str2 are referring to it. 字符串shahrooz单个副本存储在内存中,并且str1str2都在引用它。 Your int1 and int2 on the other hand are being boxed which is taking the value type int and placing it inside an object . 另一方面,您的int1int2装箱 ,其值类型为int并将其放置在object Each int (or any other value type) boxed gets put in its own box with its own address. 装箱的每个int (或任何其他值类型)都将放入具有其自身地址的框内。

Now the default behavior of == when given two reference types (like object ) is to just compare the memory address (to see if they refer to the same object), and this is what's happening. 现在,当给定两种引用类型(例如object )时, ==的默认行为是仅比较内存地址(以查看它们是否引用同一对象),这就是正在发生的情况。 In the case of the strings, it's the same object. 对于字符串,它是同一对象。 In the case of the ints, it isn't. 如果是整数,则不是。

As others have suggested, using Equals will give the desired result because Object.Equals is virtual and can be overridden, hence calling the appropriate int.Equals when given int and string.Equals when given a string. 如其他人建议的,使用Equals将得到期望的结果,因为Object.Equalsvirtual和可以被覆盖,因此,调用适当的int.Equals给予时intstring.Equals给定的字符串时。

From https://msdn.microsoft.com/en-us/library/53k8ybth.aspx?f=255&MSPPError=-2147217396 来自https://msdn.microsoft.com/zh-cn/library/53k8ybth.aspx?f=255&MSPPError=-2147217396

For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. 对于预定义的值类型,相等运算符(==)如果其操作数的值相等,则返回true,否则返回false。 For reference types other than string, == returns true if its two operands refer to the same object. 对于字符串以外的引用类型,如果==的两个操作数引用同一对象,则==返回true。 For the string type, == compares the values of the strings. 对于字符串类型,==比较字符串的值。

First time I misunderstood this quote, what it means actually is that there are 2 different operators in this case, one for object, and one for string. 第一次我误解了这句话,实际上是在这种情况下有两种不同的运算符,一种是对象,另一种是字符串。

The object operator compares the instance reference, and string operator compares the value of both strings. 对象运算符比较实例引用,而字符串运算符比较两个字符串的值。

In this case 在这种情况下

Console.WriteLine(str1 == str2); // True, becuase of compiler optimizations.
// you can test it with:
Console.WriteLine(object.ReferenceEquals(str1, str2)); // this is true

But if you do 但是如果你这样做

object s1 = "shahrooz";
object s2 = "shah";
s2 += "rooz";

Console.WriteLine(s1 == s2);
//You get false, becuase compiler now can't optimize this.

Said that

int1 == int2 // False, because they reference a different instance
int1 == int1 // True, same instance.

It is because operators can't be virtual , because of that you are calling the == operator on Object . 这是因为运算符不能是virtual ,因此您要在Object上调用==运算符。

The == operator for object compares references. 对象的==运算符比较引用。 For structs (like int ) when cast to a object it will "box" the struct in to a class reference. 对于结构(如int ),当将其强制转换为object ,会将结构“装箱”到类引用中。 The code 编码

object int1 = 1;
object int2 = 1;

causes two boxes to be made so when you call == on the box it sees the other side is not the same box so it returns false. 导致创建两个框,因此当您在框上调用==时,会看到另一侧不是同一框,因此返回false。

Strings are already reference types so they don't get a extra box made when they are put in to a object . 字符串已经是引用类型,因此当放入一个object时,它们不会产生一个多余的盒子。 However the compiler treats them special, in the following code 但是,在下面的代码中,编译器将它们视为特殊的

object str1 = "shahrooz";
object str2 = "shahrooz";

The compiler only makes one shahrooz string in memory and assigns it to both str1 and str2 . 编译器仅在内存中创建一个shahrooz字符串,并将其分配给str1str2 This is why it returns true when you compare them. 这就是为什么当您比较它们时返回true原因。

If you did the code 如果您执行了代码

public static void Main()
{
    object str1 = "shahrooz";
    object str2 = "shah" + Console.ReadLine();

    Console.WriteLine(str1 == str2);
    Console.ReadLine();
}

and typed in rooz you would get false as your result because you now have two different string references even though they have the same string content. 并输入rooz会导致结果false ,因为您现在拥有两个不同的字符串引用,即使它们具有相同的字符串内容。

use the method Equals instead of == , that does check if the Equals method was overloaded on derived classes and will unbox structs to compare them. 使用Equals方法而不是== ,它会检查Equals方法是否在派生类上重载,并且将对结构进行拆箱以进行比较。

It is because string is immutable and they point to same references from string intern pool and its not true for any other value type or reference types as they create new references every time you initialize a new object. 这是因为string是不可变的,并且它们指向来自字符串内部存储池的相同引用,并且对于任何其他值类型或引用类型而言,它不是正确的,因为每次初始化新对象时它们都会创建新引用。

To prove above we check references of two strings initialized separately: 为了证明上述,我们检查了分别初始化的两个字符串的引用:

object str1 = "shahrooz";
object str2 = "shahrooz";

Console.WriteLine(object.ReferenceEquals(str1, str2)); //True
Console.WriteLine(object.ReferenceEquals(int1, int2)); //False

Which proves that same strings hold same reference but other objects don't. 证明相同的字符串具有相同的引用,而其他对象则不具有。 Its not true for all the reference types but strings are treated as special classes. 对于所有引用类型,并非都是如此,但是字符串被视为特殊类。

On the other hand for any other reference types: 另一方面,对于任何其他引用类型:

Test a = new Test { Num=1, Str="shahrooz"};
Test b = new Test { Num=1, Str="shahrooz"};

a.Equals(b); //False  
object.ReferenceEquals(a,b);  //False

But if you do, 但是如果你这样做

Test c = a;
a.Equals(c); //True 
object.ReferenceEquals(a,c) //True.

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

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