== 与 .NET 中的 Object.Equals(object)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/112625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
== vs. Object.Equals(object) in .NET
提问by Matthew Scharley
So, when I was a comparative novice to the novice I am right now, I used to think that these two things were syntactic sugar for each other, i.e. that using one over the other was simply a personal preference. Over time, I'm come to find that these two are not the same thing, even in a default implementation (see thisand this). To further confuse the matter, each can be overridden/overloaded separately to have completely different meanings.
所以,当我和现在的新手比较菜鸟时,我曾经认为这两个东西是彼此的语法糖,即使用一个而不是另一个只是个人偏好。随着时间的推移,我开始发现这两者并不是一回事,即使在默认实现中也是如此(参见this和this)。为了进一步混淆问题,每个都可以单独覆盖/重载以具有完全不同的含义。
Is this a good thing, what are the differences, and when/why should you use one over the other?
这是一件好事吗,有什么区别,什么时候/为什么应该使用一个而不是另一个?
采纳答案by aku
MSDN has clear and solid descriptions of both things.
MSDN 对这两件事都有清晰而可靠的描述。
Guidelines for Overriding Equals() and Operator ==
Is this a good thing, what are the differences, and when/why should you use one over the other?
这是一件好事吗,有什么区别,什么时候/为什么应该使用一个?
How can it be "good" or "bad" thing? One - method, another - operator. If reference equality is not sufficient, overload them, otherwise leave them as is. For primitive types they just work out of box.
它怎么可能是“好”或“坏”的东西?一种 - 方法,另一种 - 运算符。如果引用相等不充分,则重载它们,否则保持原样。对于原始类型,它们只是开箱即用。
回答by molasses
string x = "hello";
string y = String.Copy(x);
string z = "hello";
To test if xpoints to the same object as y:
要测试是否x指向与 相同的对象y:
(object)x == (object)y // false
x.ReferenceEquals(y) // false
x.ReferenceEquals(z) // true (because x and z are both constants they
// will point to the same location in memory)
To test if xhas the same string value as y:
要测试是否x具有与以下相同的字符串值y:
x == y // true
x == z // true
x.Equals(y) // true
y == "hello" // true
Note that this is different to Java.
In Java the ==operator is not overloaded so a common mistake in Java is:
请注意,这与 Java 不同。在 Java 中,==运算符不会重载,因此Java 中的一个常见错误是:
y == "hello" // false (y is not the same object as "hello")
For string comparison in Java you need to always use .equals()
对于 Java 中的字符串比较,您需要始终使用 .equals()
y.equals("hello") // true
回答by ToolmakerSteve
Microsoft says that class implementers should make ==behave as similarly as possible to Equals:
微软表示,类实现者的==行为应该尽可能类似于Equals:
DO ensure that Object.Equals and the equality operators have exactly the same semantics
确保 Object.Equals 和相等运算符具有完全相同的语义
from http://msdn.microsoft.com/en-us/library/vstudio/7h9bszxx(v=vs.110).aspx
来自http://msdn.microsoft.com/en-us/library/vstudio/7h9bszxx(v=vs.110).aspx
If you want to be certain you are getting IDENTITYcomparison (when comparing references), then use ReferenceEqualsinstead.
如果您想确定您正在获得IDENTITY比较(在比较引用时),请ReferenceEquals改用。
If a class implementor does not override ==, then static method is looked for, at compile time, in base classes. If this search reaches Object, then Object.==is used. For classes, this is same as ReferenceEquals.
如果类实现者没有覆盖==,则在编译时在基类中查找静态方法。如果此搜索达到Object,则Object.==使用。对于类,这与ReferenceEquals.
If class documentation is uncertain as to whether a given class (from a vendor other than Microsoft presumably) implements ==as Equalsor ReferenceEquals(or it could in theory be different than both of those),
I sometimes avoid ==. Instead, I use the less readable Equals(a, b)or ReferenceEquals(a, b), depending on which meaning I want.
如果类文档不确定给定的类(可能来自 Microsoft 以外的供应商)是否实现==为Equalsor ReferenceEquals(或者理论上它可能与这两者都不同),
我有时会避免==. 相反,我使用可读性较差的Equals(a, b)或ReferenceEquals(a, b),具体取决于我想要的含义。
OTOH, ps2goatmakes a good point that using ==avoids exception if first operand is null (because ==is a static operator). This is an argument in favor of using ==.
OTOH,ps2goat提出了一个很好的观点,即==如果第一个操作数为空(因为==是一个静态运算符),则使用可以避免异常。这是一个支持使用==.
Removed controversial commentary regarding ==
删除了有争议的评论 ==
UPDATEA recent Microsoft doc quote, from .Net 4.7.2 retrieved Feb. 2019, shows they stillintend the two to behave similarly:
更新来自 2019 年 2 月检索的 .Net 4.7.2 的最近 Microsoft 文档引用表明,他们仍然希望两者的行为相似:
Some languages such as C# and Visual Basic support operator overloading. When a type overloads the equality operator, it must also override the Equals(Object) method to provide the same functionality. This is typically accomplished by writing the Equals(Object) method in terms of the overloaded equality operator, as in the following example.
某些语言(例如 C# 和 Visual Basic)支持运算符重载。当类型重载相等运算符时,它还必须覆盖 Equals(Object) 方法以提供相同的功能。这通常是通过根据重载的相等运算符编写 Equals(Object) 方法来实现的,如下例所示。
NOTE: See other answers for the consequences of ==being a static method vs Equalsbeing an instance method. I'm not claiming behavior is identical; I'm observing that Microsoft recommends making the two as similar as possible.
注意:有关==作为静态方法与Equals作为实例方法的后果,请参阅其他答案。我并不是声称行为是相同的;我观察到 Microsoft 建议使两者尽可能相似。
回答by ps2goat
I was going to post this as a comment on the accepted answer, but I think this deserves to be considered when determining which route to take.
我打算将此作为对已接受答案的评论发布,但我认为在确定采取哪条路线时值得考虑这一点。
dotnetfiddle: https://dotnetfiddle.net/gESLzO
dotnetfiddle: https://dotnetfiddle.net/gESLzO
Fiddle code:
小提琴代码:
Object a = null;
Object b = new Object();
// Ex 1
Console.WriteLine(a == b);
// Ex 2
Console.WriteLine(b == a);
// Ex 3
Console.WriteLine(b.Equals(a));
// Ex 4
Console.WriteLine(a.Equals(b));
The first 3 WriteLine examples will work, but the fourth throws an exception. 1 and 2 use ==, which is a static method that does not require either object to be instantiated.
前 3 个 WriteLine 示例将起作用,但第四个示例引发异常。1 和 2 使用==,这是一个静态方法,不需要实例化任何一个对象。
Example 3 works because bis instantiated.
示例 3 之所以有效,b是因为已实例化。
Example 4 fails because ais null, and thus a method can not be called on a null object.
示例 4 失败,因为ais null,因此无法在空对象上调用方法。
Because I try to code as lazily as possible, I use ==, especially when working with scenarios where either object (or both) can be null. If I didn't, I'd have to do a null check, first, before being able to call .Equals().
因为我尝试尽可能懒惰地编码,所以我使用==,尤其是在处理任一对象(或两者)都可以为空的场景时。如果我没有,我必须先做一个空检查,然后才能调用.Equals().
回答by Andrew Rondeau
To answer this, we must describe the four kinds of object equivalence:
为了回答这个问题,我们必须描述四种对象等价:
Reference Equality, object.ReferenceEquals(a, b): The two variables point to the same exact object in RAM. (If this were C, both variables would have the same exact pointer.)
Interchangeability, a == b: The two variables refer to objects that are completely interchangeable. Thus, when a == b, Func(a,b) and Func(b,a) do the same thing.
Semantic Equality, object.Equals(a, b): At this exact moment in time, the two objects mean the same thing.
Entity equality, a.Id == b.Id: The two objects refer to the same entity, such as a database row, but don't have to have the same contents.
Reference Equality, object.ReferenceEquals(a, b):这两个变量指向 RAM 中的同一个对象。(如果这是 C,则两个变量将具有完全相同的指针。)
Interchangeability, a == b:这两个变量指的是完全可以互换的对象。因此,当 a == b 时,Func(a,b) 和 Func(b,a) 做同样的事情。
Semantic Equality, object.Equals(a, b):在这个确切的时刻,这两个对象意味着同一件事。
实体相等,a.Id == b.Id:两个对象引用同一个实体,例如数据库行,但不必具有相同的内容。
As a programmer, when working with an object of a known type, you need to understand the kind of equivalence that's appropriate for your business logic at the specific moment of code that you're in.
作为程序员,在处理已知类型的对象时,您需要了解在您所处的特定代码时刻适合您的业务逻辑的等效项类型。
The simplest example about this is the string versus StringBuilder types. String overrides ==, StringBuilder does not:
最简单的例子是字符串与 StringBuilder 类型。字符串覆盖 ==,StringBuilder 不会:
var aaa1 = "aaa";
var aaa2 = $"{'a'}{'a'}{'a'}";
var bbb = "bbb";
// False because aaa1 and aaa2 are completely different objects with different locations in RAM
Console.WriteLine($"Object.ReferenceEquals(aaa1, aaa2): {Object.ReferenceEquals(aaa1, aaa2)}");
// True because aaa1 and aaa2 are completely interchangable
Console.WriteLine($"aaa1 == aaa2: {aaa1 == aaa2}"); // True
Console.WriteLine($"aaa1.Equals(aaa2): {aaa1.Equals(aaa2)}"); // True
Console.WriteLine($"aaa1 == bbb: {aaa1 == bbb}"); // False
Console.WriteLine($"aaa1.Equals(bbb): {aaa1.Equals(bbb)}"); // False
// Won't compile
// This is why string can override ==, you can not modify a string object once it is allocated
//aaa1[0] = 'd';
// aaaUpdated and aaa1 point to the same exact object in RAM
var aaaUpdated = aaa1;
Console.WriteLine($"Object.ReferenceEquals(aaa1, aaaUpdated): {Object.ReferenceEquals(aaa1, aaaUpdated)}"); // True
// aaaUpdated is a new string, aaa1 is unmodified
aaaUpdated += 'c';
Console.WriteLine($"Object.ReferenceEquals(aaa1, aaaUpdated): {Object.ReferenceEquals(aaa1, aaaUpdated)}"); // False
var aaaBuilder1 = new StringBuilder("aaa");
var aaaBuilder2 = new StringBuilder("aaa");
// False, because both string builders are different objects
Console.WriteLine($"Object.ReferenceEquals(aaaBuider1, aaaBuider2): {Object.ReferenceEquals(aaa1, aaa2)}");
// Even though both string builders have the same contents, they are not interchangable
// Thus, == is false
Console.WriteLine($"aaaBuider1 == aaaBuilder2: {aaaBuilder1 == aaaBuilder2}");
// But, because they both have "aaa" at this exact moment in time, Equals returns true
Console.WriteLine($"aaaBuider1.Equals(aaaBuilder2): {aaaBuilder1.Equals(aaaBuilder2)}");
// Modifying the contents of the string builders changes the strings, and thus
// Equals returns false
aaaBuilder1.Append('e');
aaaBuilder2.Append('f');
Console.WriteLine($"aaaBuider1.Equals(aaaBuilder2): {aaaBuilder1.Equals(aaaBuilder2)}");
To get into more details, we can work backwards, starting with entity equality. In the case of entity equality, properties of the entity may change over time, but the entity's primary key never changes. This can be demonstrated with pseudocode:
为了获得更多细节,我们可以从实体平等开始向后工作。在实体相等的情况下,实体的属性可能会随着时间的推移而改变,但实体的主键永远不会改变。这可以用伪代码证明:
// Hold the current user object in a variable
var originalUser = database.GetUser(123);
// Update the user's name
database.UpdateUserName(123, user.Name + "son");
var updatedUser = database.GetUser(123);
Console.WriteLine(originalUser.Id == updatedUser.Id); // True, both objects refer to the same entity
Console.WriteLine(Object.Equals(originalUser, updatedUser); // False, the name property is different
Moving to semantic equality, the example changes slightly:
转向语义相等,示例略有变化:
var originalUser = new User() { Name = "George" };
var updatedUser = new User() { Name = "George" };
Console.WriteLine(Object.Equals(originalUser, updatedUser); // True, the objects have the same contents
Console.WriteLine(originalUser == updatedUser); // User doesn't define ==, False
updatedUser.Name = "Paul";
Console.WriteLine(Object.Equals(originalUser, updatedUser); // False, the name property is different
What about interchangeability? (overriding ==) That's more complicated. Let's build on the above example a bit:
互换性怎么样?(覆盖==)那更复杂。让我们以上面的例子为基础:
var originalUser = new User() { Name = "George" };
var updatedUser = new User() { Name = "George" };
Console.WriteLine(Object.Equals(originalUser, updatedUser); // True, the objects have the same contents
// Does this change updatedUser? We don't know
DoSomethingWith(updatedUser);
// Are the following equivalent?
// SomeMethod(originalUser, updatedUser);
// SomeMethod(updatedUser, originalUser);
In the above example, DoSomethingWithUser(updatedUser) might change updatedUser. Thus we can no longer guarantee that the originalUser and updatedUser objects are "Equals." This is why User does not override ==.
在上面的例子中,DoSomethingWithUser(updatedUser) 可能会改变 updatedUser。因此我们不能再保证 originalUser 和 updatedUser 对象是“Equals”。这就是用户不覆盖 == 的原因。
A good example for when to override == is with immutable objects. An immutable object is an object who's publicly-visible state (properties) never change. The entire visible state must be set in the object's constructor. (Thus, all properties are read-only.)
何时覆盖 == 的一个很好的例子是使用不可变对象。不可变对象是公开可见的状态(属性)永远不会改变的对象。整个可见状态必须在对象的构造函数中设置。(因此,所有属性都是只读的。)
var originalImmutableUser = new ImmutableUser(name: "George");
var secondImmutableUser = new ImmutableUser(name: "George");
Console.WriteLine(Object.Equals(originalImmutableUser, secondImmutableUser); // True, the objects have the same contents
Console.WriteLine(originalImmutableUser == secondImmutableUser); // ImmutableUser defines ==, True
// Won't compile because ImmutableUser has no setters
secondImmutableUser.Name = "Paul";
// But this does compile
var updatedImmutableUser = secondImmutableUser.SetName("Paul"); // Returns a copy of secondImmutableUser with Name changed to Paul.
Console.WriteLine(object.ReferenceEquals(updatedImmutableUser, secondImmutableUser)); // False, because updatedImmutableUser is a different object in a different location in RAM
// These two calls are equivalent because the internal state of an ImmutableUser can never change
DoSomethingWith(originalImmutableUser, secondImmutableUser);
DoSomethingWith(secondImmutableUser, originalImmutableUser);
Should you override == with a mutable object? (That is, an object who's internal state can change?) Probably not. You would need to build a rather complicated event system to maintain interchangeability.
你应该用可变对象覆盖 == 吗?(也就是说,一个内部状态可以改变的对象?)可能不会。您需要构建一个相当复杂的事件系统来保持可互换性。
In general, I work with a lot of code that uses immutable objects, so I override == because it's more readable than object.Equals. When I work with mutable objects, I don't override == and rely on object.Equals. Its the programmer's responsibility to know if the objects they are working with are mutable or not, because knowing if something's state can change should influence how you design your code.
一般来说,我使用了很多使用不可变对象的代码,所以我覆盖 == 因为它比 object.Equals 更具可读性。当我使用可变对象时,我不会覆盖 == 并依赖于 object.Equals。程序员有责任知道他们正在使用的对象是否可变,因为知道某些东西的状态是否可以改变应该会影响您设计代码的方式。
The default implementation of == is object.ReferenceEquals because, with mutable objects, interchangeability is only guaranteed when the variables point to the same exact object in RAM. Even if the objects have the same contents at a given point in time, (Equals returns true,) there is no guarantee that the objects will continue to be equal; thus the objects are not interchangeable. Thus, when working with a mutable object that does not override ==, the default implementation of == works, because if a == b, they are the same object, and SomeFunc(a, b) and SomeFunc(b, a) are exactly the same.
== 的默认实现是 object.ReferenceEquals,因为对于可变对象,只有当变量指向 RAM 中的相同对象时才能保证可互换性。即使对象在给定的时间点具有相同的内容,(Equals 返回 true,)也不能保证对象将继续相等;因此对象不可互换。因此,当使用不覆盖 == 的可变对象时,== 的默认实现有效,因为如果 a == b,它们是相同的对象,并且 SomeFunc(a, b) 和 SomeFunc(b, a)完全一样。
Furthermore, if a class does not define equivalence, (For example, think of a database connection, and open file handle, ect,) then the default implementation of == and Equals fall back to reference equality, because two variables of type database connection, open file handle, ect, are only equal if they are the exact instance of the database connection, open file handle, ect. Entity equality might make sense in business logic that needs to know that two different database connections refer to the same database, or that two different file handles refer to the same file on disk.
此外,如果一个类没有定义等价,(例如,考虑一个数据库连接,并打开文件句柄等)那么 == 和 Equals 的默认实现会回退到引用相等,因为数据库连接类型的两个变量、打开文件句柄等仅在它们是数据库连接、打开文件句柄等的确切实例时才相等。在需要知道两个不同的数据库连接引用同一个数据库,或者两个不同的文件句柄引用磁盘上的同一个文件的业务逻辑中,实体相等可能是有意义的。
Now, for my soapbox moment. In my opinion, C# handles this topic in a confusing way. == should be for semantic equality, instead of the Equals method. There should be a different operator, like ===, for interchangeability, and potentially another operator, ====, for referential equality. This way, someone who's a novice, and / or writing CRUD applications, only needs to understand ==, and not the more nuanced details of interchangeability and referential equality.
现在,为了我的肥皂盒时刻。在我看来,C# 以一种令人困惑的方式处理这个话题。== 应该用于语义相等,而不是 Equals 方法。应该有一个不同的运算符,如 ===,用于可互换性,可能还有另一个运算符,====,用于引用相等。这样,新手和/或编写 CRUD 应用程序的人只需要了解 ==,而不需要了解可互换性和参照平等的更细微的细节。
回答by andrewdotnich
My understanding of the uses of both was this: use == for conceptual equality (in context, do these two arguments mean the same thing?), and .Equals for concrete equality (are these two arguments in actual fact the exact same object?).
我对两者用法的理解是:使用 == 表示概念上的相等(在上下文中,这两个参数是否意味着同一件事?),而 .Equals 表示具体相等(这两个参数实际上是完全相同的对象吗? )。
Edit: Kevin Sheffield's linked article does a better job of explaining value vs. reference equality…
编辑:凯文谢菲尔德的链接文章在解释价值与参考平等方面做得更好......
回答by Ed S.
You may want to use .Equals as someone may come along at a later time and overload them for you class.
您可能想要使用 .Equals,因为稍后可能会有人出现并为您的课程超载它们。
回答by Sonu Rajpoot
Operator == and Equals() both are same while we are comparing values instead of references. Output of both are same see below example.
当我们比较值而不是引用时,运算符 == 和 Equals() 都是相同的。两者的输出相同,请参见下面的示例。
Example
例子
static void Main()
{
string x = " hello";
string y = " hello";
string z = string.Copy(x);
if (x == y)
{
Console.WriteLine("== Operator");
}
if(x.Equals(y))
{
Console.WriteLine("Equals() Function Call");
}
if (x == z)
{
Console.WriteLine("== Operator while coping a string to another.");
}
if (x.Equals(y))
{
Console.WriteLine("Equals() Function Call while coping a string to another.");
}
}
Output:
输出:
== Operator
Equals() Function Call
== Operator while coping a string to another.
Equals() Function Call while coping a string to another.
回答by Dimitri C.
Two of the most often used types, String and Int32, implement both operator==() and Equals() as value equality (instead of reference equality). I think one can consider these two defining examples, so my conclusion is that both have identical meanings. If Microsoft states otherwise, I think they are intentionally causing confusion.
两种最常用的类型String 和 Int32将 operator==() 和 Equals() 实现为值相等(而不是引用相等)。我认为可以考虑这两个定义性示例,因此我的结论是两者具有相同的含义。如果微软另有说明,我认为他们是故意造成混乱。

