string x = "hello";
string y = String.Copy(x);
string z = "hello";
测试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)
测试x
和y
是否具有相同的字符串值:
x == y // true
x == z // true
x.Equals(y) // true
y == "hello" // true
请注意,这与Java不同。
在Java中,==
运算符没有重载,因此Java中常见的错误是:
y == "hello" // false (y is not the same object as "hello")
在Java中进行字符串比较时,您需要始终使用.equals()
y.equals("hello") // true
MSDN有关于这两个事物的清晰而可靠的描述。
这是一件好事吗,它们之间有什么区别,什么时候/为什么应该使用其中一个?
怎么可能是“好”或“坏”的事情呢?一个是方法,另一个是运算符。如果引用相等性不足够,则重载它们,否则保持原样。对于基本类型,它们可以直接使用。
x
是 null
(vb.net
中的 Nothing
),那么 x.Equals()
将会抛出异常。 - mbomb007==
的行为尽可能与 Equals
相似:
引自:http://msdn.microsoft.com/en-us/library/vstudio/7h9bszxx(v=vs.110).aspx确保 Object.Equals 和等式运算符具有完全相同的语义。
ReferenceEquals
。==
,则在编译时会在基类中寻找静态方法。如果查找到 Object
,则使用 Object.==
。对于类而言,这与 ReferenceEquals
是一样的。==
实现为 Equals
或 ReferenceEquals
(或者它理论上可能与这两个都不同),我有时会避免使用 ==
。相反,我会使用较不可读的 Equals(a, b)
或 ReferenceEquals(a, b)
,具体取决于我想要的含义。==
可以避免异常(因为 ==
是一个静态运算符)。这是使用 ==
的一个优点的论据。
==
有争议的评论
某些语言(如 C# 和 Visual Basic)支持运算符重载。当类型重载等式运算符时,它必须还要重写 Equals(Object) 方法以提供相同的功能。通常通过使用以下示例中的重载等式运算符编写 Equals(Object) 方法来完成此操作。
==
作为静态方法与 Equals
作为实例方法的后果。我并不声称行为是相同的;我观察到微软建议使这两者尽可能相似。.Equals()
(抛出异常)与使用静态运算符(不需要实例化任何操作数,没有异常,按预期工作)的区别。 - ps2goat==
运算符与Equals
行为相同; 因此我的回答中引用了这句话。然而,微软并没有强制执行这一点。如果您作为类设计者选择进行所述区分,则没有任何事情会阻止您。您能描述一个您认为有必要使用此区分的具体情况吗?此外,“您无法更改==
的结果”。是的,您可以; 为您的类定义一个==
运算符重载。通常,人们将==
实现为Equals
; 实际上,我参考的微软文档建议这样做。 - ToolmakerSteve 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));
== ,这是一个静态方法,不需要实例化任何对象。
示例3有效,因为 b 已经实例化。
示例4失败,因为 a 为 null ,因此无法在空对象上调用方法。
因为我尽可能懒惰地编码,所以我使用 == ,特别是在处理任一对象(或两者都可以)为空的情况时。如果我没有这样做,我必须先进行空检查,然后才能调用 .Equals()。
我对两者的用途的理解是:使用 == 进行概念上的相等比较(在上下文中,这两个参数是否表示相同的意思?),而使用 .Equals 进行具体的相等比较(这两个参数实际上是否是完全相同的对象?)。
编辑:Kevin Sheffield 的链接文章更好地解释了值类型和引用类型的相等性……
ReferenceEquals
是 身份
测试。如果 Equals
总是进行身份测试,那么拥有两者就没有意义了... - ToolmakerStevevar 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)}");
// 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
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
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);
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);
你可能想使用.Equals,因为有人可能会在以后重载你的类。
两种最常用的类型,String和Int32,都实现了operator==()和Equals()作为值相等(而不是引用相等)的操作符。我认为可以将这两个类型视为定义性例子,因此我的结论是它们具有相同的含义。如果Microsoft 声明相反,我认为他们是有意造成混淆。
Is
和 IsNot
来测试引用相等性;当应用于 Framework 类型时,=
和 <>
运算符将测试值相等性,如果它们能编译的话。然而,并没有什么可以阻止任何类型重载这些运算符以完全不同的含义。 - supercat当我们比较值而不是引用时,运算符==和Equals()是相同的。两者的输出结果相同,如下所示。
示例
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.");
}
}
输出:
== Operator
Equals() Function Call
== Operator while coping a string to another.
Equals() Function Call while coping a string to another.
string
与以下内容进行对比:(a)单个字符,(b)字符数组,(c)包含多个字符字段的struct
,(d)包含多个字符字段的class
。甚至可能需要展示(e)包含struct
字段或包含字符数组
字段的class
。然后进行各种赋值操作,展示何时结果仍然为true
。 - ToolmakerSteve