为什么 == 在比较两个用相同 int 值装箱的对象类型变量时不起作用
Why does == not work while comparing two object type variables boxed with same int value
在尝试用 C# 实现一个简单的单链表时,我注意到 ==
在比较两个用 int 值装箱的对象类型变量时不起作用,但 .Equals
起作用。
想检查为什么会这样。
下面的代码片段是通用对象类型数据 属性
public class Node {
/// <summary>
/// Data contained in the node
/// </summary>
private object Data { get; set; };
}
下面的代码遍历单向链表,寻找一个object类型的值-
/// <summary>
/// <param name="d">Data to be searched in all the nodes of a singly linked list
/// Traverses through each node of a singly linked list and searches for an element
/// <returns>Node if the searched element exists else null </returns>
public Node Search(object d)
{
Node temp = head;
while (temp != null)
{
if (temp.Data.Equals(d))
{
return temp;
}
temp = temp.Next;
}
return null;
}
但是,如果我替换
temp.Data.Equals(d)
与
temp.Data == d
它停止工作,即使 temp.Data
和 d
都具有值“3”。 ==
对对象类型变量不起作用的任何原因?
这是 Main 函数的片段 -
SinglyLinkedList list = new SinglyLinkedList();
list.Insert(1);
list.Insert(2);
list.Insert(3);
list.Insert(4);
list.Insert(5);
list.Print();
Node mid = list.Search(3);
我相信因为我正在传递一个 int 值 3
并且 Search 方法需要一个对象类型,所以它会成功地将 3 作为对象类型装箱。但是,不确定为什么 ==
不起作用但 .Equals
起作用。
==
运算符是否仅对值类型重载?
这是因为 ==
的 System.Object
实现测试引用相等性,就像静态 Equals(object, object)
一样,而实例 Equals(object)
被重载,所以它检查实际值。
当您对一个值类型进行两次装箱时,您会得到两个不同的实例,因此引用相等性当然会失败。
运算符是静态的,在编译时绑定,因此没有动态调度。即使字符串已经是引用类型,因此在分配给对象类型变量时不会装箱,如果其中一个操作数的静态类型不是 string
.
有两个原因:
Equals
不受 ==
的限制,反之亦然,默认情况下检查引用相等性:
您可以在 .Equals
vs ==
的规格中阅读:
By default, the operator ==
tests for reference equality by determining if two references indicate the same object, so reference types do not need to implement operator ==
in order to gain this functionality. When a type is immutable, meaning the data contained in the instance cannot be changed, overloading operator ==
to compare value equality instead of reference equality can be useful because, as immutable objects, they can be considered the same as long as they have the same value. Overriding operator ==
in non-immutable types is not recommended.
Overloaded operator ==
implementations should not throw exceptions. Any type that overloads operator ==
should also overload operator !=
.
尽管如果您不同时覆盖 !=
编译器会抛出错误,并且会警告您最好同时覆盖 .Equals
和 .GetHashCode
.
所以 overriding/overloading .Equals
、==
和 !=
是不同的东西。覆盖 .Equals
对重载 ==
和 !=
没有影响。毕竟 ==
是自定义运算符。尽管这样做并不明智,但您可以将其用于除相等性检查之外的其他目的。
更多运算符在 编译时解析:
以下面的csharp
交互式shell程序为例:
$ csharp
Mono C# Shell, type "help;" for help
Enter statements below.
csharp> public class Foo {
>
> public int data;
>
> public static bool operator == (Foo f1, Foo f2) {
> return f1.data == f2.data;
> }
>
> public static bool operator != (Foo f1, Foo f2) {
>
> return f1.data != f2.data;
> }
>
> }
(1,15): warning CS0660: `Foo' defines operator == or operator != but does not override Object.Equals(object o)
(1,15): warning CS0661: `Foo' defines operator == or operator != but does not override Object.GetHashCode()
csharp> object f = new Foo();
csharp> object f2 = new Foo();
csharp> f == f2
false
csharp> Foo f3 = f as Foo;
csharp> Foo f4 = f2 as Foo;
csharp> f3 == f4
true
如您所见,如果将对象称为 object
或 Foo
,==
会给出不同的结果。由于您使用了 object
,因此 C# 可以在编译时进行的唯一绑定是具有引用相等性的绑定。
运算符==
就像一个根据编译时类型选择的重载静态函数。在您的情况下,值的类型是 Object
,==
运算符为此实现引用相等性。
另一方面,.Equals
是虚拟的和覆盖的,所以它会根据实际类型进行比较。
在尝试用 C# 实现一个简单的单链表时,我注意到 ==
在比较两个用 int 值装箱的对象类型变量时不起作用,但 .Equals
起作用。
想检查为什么会这样。
下面的代码片段是通用对象类型数据 属性
public class Node {
/// <summary>
/// Data contained in the node
/// </summary>
private object Data { get; set; };
}
下面的代码遍历单向链表,寻找一个object类型的值-
/// <summary>
/// <param name="d">Data to be searched in all the nodes of a singly linked list
/// Traverses through each node of a singly linked list and searches for an element
/// <returns>Node if the searched element exists else null </returns>
public Node Search(object d)
{
Node temp = head;
while (temp != null)
{
if (temp.Data.Equals(d))
{
return temp;
}
temp = temp.Next;
}
return null;
}
但是,如果我替换
temp.Data.Equals(d)
与 temp.Data == d
它停止工作,即使 temp.Data
和 d
都具有值“3”。 ==
对对象类型变量不起作用的任何原因?
这是 Main 函数的片段 -
SinglyLinkedList list = new SinglyLinkedList();
list.Insert(1);
list.Insert(2);
list.Insert(3);
list.Insert(4);
list.Insert(5);
list.Print();
Node mid = list.Search(3);
我相信因为我正在传递一个 int 值 3
并且 Search 方法需要一个对象类型,所以它会成功地将 3 作为对象类型装箱。但是,不确定为什么 ==
不起作用但 .Equals
起作用。
==
运算符是否仅对值类型重载?
这是因为 ==
的 System.Object
实现测试引用相等性,就像静态 Equals(object, object)
一样,而实例 Equals(object)
被重载,所以它检查实际值。
当您对一个值类型进行两次装箱时,您会得到两个不同的实例,因此引用相等性当然会失败。
运算符是静态的,在编译时绑定,因此没有动态调度。即使字符串已经是引用类型,因此在分配给对象类型变量时不会装箱,如果其中一个操作数的静态类型不是 string
.
有两个原因:
Equals
不受==
的限制,反之亦然,默认情况下检查引用相等性:您可以在
.Equals
vs==
的规格中阅读:By default, the operator
==
tests for reference equality by determining if two references indicate the same object, so reference types do not need to implement operator==
in order to gain this functionality. When a type is immutable, meaning the data contained in the instance cannot be changed, overloading operator==
to compare value equality instead of reference equality can be useful because, as immutable objects, they can be considered the same as long as they have the same value. Overriding operator==
in non-immutable types is not recommended.Overloaded operator
==
implementations should not throw exceptions. Any type that overloads operator==
should also overload operator!=
.尽管如果您不同时覆盖
!=
编译器会抛出错误,并且会警告您最好同时覆盖.Equals
和.GetHashCode
.所以 overriding/overloading
.Equals
、==
和!=
是不同的东西。覆盖.Equals
对重载==
和!=
没有影响。毕竟==
是自定义运算符。尽管这样做并不明智,但您可以将其用于除相等性检查之外的其他目的。更多运算符在 编译时解析:
以下面的
csharp
交互式shell程序为例:$ csharp Mono C# Shell, type "help;" for help Enter statements below. csharp> public class Foo { > > public int data; > > public static bool operator == (Foo f1, Foo f2) { > return f1.data == f2.data; > } > > public static bool operator != (Foo f1, Foo f2) { > > return f1.data != f2.data; > } > > } (1,15): warning CS0660: `Foo' defines operator == or operator != but does not override Object.Equals(object o) (1,15): warning CS0661: `Foo' defines operator == or operator != but does not override Object.GetHashCode() csharp> object f = new Foo(); csharp> object f2 = new Foo(); csharp> f == f2 false csharp> Foo f3 = f as Foo; csharp> Foo f4 = f2 as Foo; csharp> f3 == f4 true
如您所见,如果将对象称为
object
或Foo
,==
会给出不同的结果。由于您使用了object
,因此 C# 可以在编译时进行的唯一绑定是具有引用相等性的绑定。
运算符==
就像一个根据编译时类型选择的重载静态函数。在您的情况下,值的类型是 Object
,==
运算符为此实现引用相等性。
另一方面,.Equals
是虚拟的和覆盖的,所以它会根据实际类型进行比较。