C#中Python的id()等价物是什么?
有没有C#类似于Python的id()的功能?如果没有,我该如何测试一个对象是否发生了变化?比如,在Python中,有一个不可变的对象:
>>> s = "abc"
>>> id(s)
11172320
>>> s += "d"
>>> id(s)
18632928
还有一个可变的对象:
>>> a = [1, 2, 3]
>>> id(a)
11259656
>>> a += [4]
>>> id(a)
11259656
编辑 - 到目前为止,大部分回答都是关于比较函数/运算符的,但我更关心的是被比较的值。我最开始没有说清楚这一点,现在我接受Object.ReferenceEquals
作为答案。
5 个回答
我觉得你问的问题不太对。我的回答虽然详细,但这里给你个简单的总结:
- C#中没有和
id
完全相同的东西。 - 你可以通过指针在C#中获取对象的地址,但不建议这样做来解决你的问题。
- 方法
object.ReferenceEquals
做的事情和你想做的有点相似。 - 你想解决的问题在C#中并不存在,和Python的情况不一样。
- 你在Python中使用
id
的方式在这里也不能解决问题。
首先,我会引用一下关于id
的文档,因为大多数人似乎没有看过。请一定要阅读这个,因为我后面的回答只有在你知道id
的作用时才有意义(而且,它并不是用来生成哈希码的):
返回一个对象的“身份”。这是一个整数(或长整数),在对象的生命周期内是唯一且不变的。两个生命周期不重叠的对象可能会有相同的id()值。
CPython实现细节:这是对象的地址。
C#没有和id
相同的东西,但可以通过在不安全模式下获取对象的指针来得到对象的地址。
unsafe
{
IntPtr x = (IntPtr)(&v);
Console.WriteLine(x);
}
不过你不应该这样做。在C#中,你很少需要使用不安全的代码,如果你这样做,调用你代码的其他代码也会变得不安全。还有其他方法可以解决你的问题,不需要用到不安全的代码。此外,在.NET中(和Python不同),垃圾回收器会在内存中移动对象,所以如果你想要一个在对象整个生命周期内保持不变的身份,内存地址对你没有用。你应该创建一个只读属性,比如叫Id
。
在C#中,还有一种不使用不安全代码的方法是通过Object.ReferenceEquals
来测试两个变量是否引用同一个对象。不过你可能也不应该这样做。C#没有像Python那样的模糊性。要把一个变量指向一个新对象,你使用=
运算符。调用一个方法几乎总是不会改变引用,所以你不需要担心。在C#中,x += y;
几乎等同于x = x + y
,而且你不能像在Python中那样改变它。
另外,正如文档中提到的,你的Python示例是有问题的——id
不能可靠地用来测试一个对象是否发生了变化。举个例子:
>>> s='abc'
>>> id(s)
37822208
>>> s+='d'
>>> id(s)
61711680 # Changes
>>> s+='e'
>>> id(s)
61711680 # Oops... doesn't change even though the value changed.
在Python中,如果你需要比较两个对象以查看它们是否是同一个对象(而且你可能不应该这样做),那么使用is
,它是Python中object.ReferenceEquals
的等价物。id
只保证在对象的生命周期内是常量。如上所示,id
并不保证不同对象的id
是不同的。特别是如果其中一个对象不再存在,你可能会(并且有时会)因为内存的重用而得到相同的id
。因此,在这里使用id
真的是个坏主意。
总结
别这么做。
你可以用 Object.ReferenceEquals
来测试对象的身份。
你可以使用 Object.ReferenceEquals()
这个函数:
这个函数用来判断指定的对象实例是否是同一个实例。
借用一下你提到的Python例子:
List<int> listA = new List<int> { 1, 2, 3 };
List<int> listB = listA;
listA.Add(4);
bool equal = object.ReferenceEquals(listA, listB);
equal
的值会是 true
。