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

bwleehnv  于 2023-01-09  发布在  其他
关注(0)|答案(3)|浏览(95)

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

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

由于在C#中检查对象的内存地址似乎是不可能的,那么在调试代码时,如何验证我正在处理的是同一个对象还是另一个对象呢?

9w11ddsr

9w11ddsr1#

在C#中,对象是在垃圾收集过程中移动的,你不能简单地获取它的地址,因为当垃圾收集堆被压缩时,地址会改变。
在C#中处理指针需要不安全的代码,而您离开了安全代码的领域,基本上使其与C++一样不安全。
您可以使用windbg这样的调试器,它显示对象的内存地址--但是当GC移动它们时,它们仍然会改变。
如果您想查看是否创建了类的新示例,为什么不在构造函数中设置断点呢?

t1qtbnec

t1qtbnec2#

我对“托马斯”上面的回答深信不疑。
可以向对象添加唯一标识符(如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;
    }
}
rseugnpd

rseugnpd3#

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

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

您不需要地址,因为您需要的只是每个对象的***助记符***,以便在故障排除过程中识别它。为此,您有以下选项:
1.创建一个发布唯一id的singleton,在每个对象的构造函数中调用这个singleton来获得一个唯一id,将id存储在对象中,并将id包含在对象的ToString()方法中,或者包含在任何其他可能用于调试显示的方法中。
1.使用System.Runtime.Serialization.ObjectIDGenerator类,它或多或少地做了单例id生成器所做的事情,但是以一种更高级、可能更容易使用的方式(我没有使用它的个人经验,所以我不能给予更多关于它的建议)。
1.使用System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode( object )方法,该方法返回在其他圈子中称为***对象的标识散列代码***的内容。它保证在对象的整个生命周期中保持不变,但不保证在所有对象中是唯一的。然而,由于它是32位长,如果另一个对象碰巧得到相同的散列代码,那将是地狱中的一个寒冷的日子。所以它将很好地满足您所有的故障排除目的。
帮你自己一个忙,用十六进制显示你的对象的身份散列码;该数字将比十进制更短,并且具有更广泛的数字种类,因此在故障排除时更容易保留在短期记忆中。

相关问题