我总是在处理同一个对象吗?



我正在开发一个TCP套接字相关的应用程序,其中我创建的对象引用了一个System.Net.Sockets.Socket对象。后一个对象似乎变成了null,为了理解为什么,我想检查一下我自己的对象是否被重新创建。为此,我想到了最简单的方法,即检查this的内存地址。但是,当将此添加到监视窗口时,我得到以下错误消息:

Name    Value
&this   error CS0211: Cannot take the address of the given expression

因为在c#中检查对象的内存地址似乎是不可能的,我怎么能在调试代码时验证我正在处理相同或另一个对象?

在c#中,对象在垃圾收集期间被移动。您不能简单地获取它的地址,因为地址在GC堆压缩时发生了变化。

在c#中处理指针需要不安全的代码,你离开了安全代码的领域,基本上使它和c++一样不安全。

你可以使用像windbg这样的调试器,它可以显示对象的内存地址——但是当GC移动它们时,它们仍然会改变。

如果你想看看你的类的新实例是否被创建,为什么不在构造函数中设置一个断点?

我相信@thomas的回答。

你可以添加一个唯一的标识符(比如GUID)属性到你的对象,并使用它来确定你是否有相同的对象。

您可以重写Equals方法来比较两个对象,如果它们与下面相同。

public class MyClass
{
public Guid Id { get; } = Guid.NewGuid();
public override bool Equals(object obj)
{
return obj is MyClass second && this.Id == second.Id;
}
}

如前所述,对象的地址不是一种可行的方法来推断像DotNet这样的垃圾收集虚拟机中的对象。在DotNet中,如果您使用fixed关键字、unsafe块或GCHandle.Alloc(),您可能有机会观察对象的地址,但这些都非常糟糕,它们将对象固定在内存中,因此它们不能被垃圾收集,这是您绝对不想要的。一旦你解除了一个对象的固定,那么它的地址就可以自由地改变了,所以你不能跟踪它。

幸运的是,您不需要这些!

你不需要地址,因为你只需要一个助记符,以便在故障排除过程中识别该对象。为此,您有以下选项:

  1. 创建一个发出唯一id的单例,并在每个对象的构造函数中调用该单例来获得唯一id,将id存储在对象中,并将id包含在对象的ToString()方法中,或者在您可能用于调试显示的任何其他方法中。

  2. 使用System.Runtime.Serialization.ObjectIDGenerator类,它或多或少地做了单例id生成器会做的事情,但以一种更高级,可能更容易使用的方式。(我没有使用它的个人经验,所以我不能给出更多的建议。)

  3. 使用System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode( object )方法,它返回在其他圈子中已知的身份哈希码对象的。它保证在对象的整个生命周期中保持不变,但不保证在所有对象中是唯一的。然而,由于它是32位长,在另一个对象碰巧发出相同的哈希码之前,它将是地狱里的寒冷的一天,所以它将很好地满足您的所有故障排除目的。

帮你自己一个忙,用十六进制显示你的对象的身份哈希码;该数字将比十进制更短,并且有更多的数字种类,因此在故障排除时更容易在短期记忆中保留。

相关内容

最新更新