在C#中的对象的内存地址

我有一个前段时间写的函数(对于.NET 3.5),现在我已经升级到4.0我不能得到它的工作。

function是:

public static class MemoryAddress { public static string Get(object a) { GCHandle handle = GCHandle.Alloc(a, GCHandleType.Pinned); IntPtr pointer = GCHandle.ToIntPtr(handle); handle.Free(); return "0x" + pointer.ToString("X"); } } 

现在,当我叫它 – MemoryAddress.Get(新车(“蓝”))

 public class Car { public string Color; public Car(string color) { Color = color; } } 

我得到的错误:“对象包含非原始或不可blittable数据”。

为什么它不再工作? 我怎样才能获得pipe理对象的内存地址?

您可以使用GCHandleType.Weak而不是固定。 另一方面,还有另一种方法来获取指向对象的指针:

 object o = new object(); TypedReference tr = __makeref(o); IntPtr ptr = **(IntPtr**)(&tr); 

要求不安全的块,是非常非常危险的,不应该被使用。 ☺

您应该调用GetHashCode() ,而不是这个代码,它将为每个实例返回一个(希望)唯一的值。

你也可以使用ObjectIDGenerator类 ,它是唯一的。

如果你不是真的需要内存地址,而是一些唯一标识pipe理对象的方法,那么有一个更好的解决scheme:

 using System.Runtime.CompilerServices; public static class Extensions { private static readonly ConditionalWeakTable<object, RefId> _ids = new ConditionalWeakTable<object, RefId>(); public static Guid GetRefId<T>(this T obj) where T: class { if (obj == null) return default(Guid); return _ids.GetOrCreateValue(obj).Id; } private class RefId { public Guid Id { get; } = Guid.NewGuid(); } } 

这是线程安全的,内部使用弱引用,所以你不会有内存泄漏。

您可以使用任何您喜欢的密钥生成方法。 我在这里使用Guid.NewGuid() ,因为它很简单,线程安全。

更新

我继续创build了一个Nuget包Overby.Extensions.Attachments ,其中包含一些用于将对象附加到其他对象的扩展方法。 有一个名为GetReferenceId()的扩展,有效地做了这个答案中的代码显示。

当释放该句柄时,垃圾收集器可以自由移动被固定的内存。 如果你有一个指向应该被固定的内存的指针,并且你取消了这个内存的locking,那么所有的投注都是closures的。 这在3.5的所有工作可能只是运气。 JIT编译器和4.0版运行时可能会更好地进行对象生命周期分析。

如果你真的想这样做,你可以使用try/finally来防止对象被固定,直到你使用它之后:

 public static string Get(object a) { GCHandle handle = GCHandle.Alloc(a, GCHandleType.Pinned); try { IntPtr pointer = GCHandle.ToIntPtr(handle); return "0x" + pointer.ToString("X"); } finally { handle.Free(); } } 

这适用于我…

 #region AddressOf /// <summary> /// Provides the current address of the given object. /// </summary> /// <param name="obj"></param> /// <returns></returns> [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf(object obj) { if (obj == null) return System.IntPtr.Zero; System.TypedReference reference = __makeref(obj); System.TypedReference* pRef = &reference; return (System.IntPtr)pRef; //(&pRef) } /// <summary> /// Provides the current address of the given element /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf<T>(T t) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct { System.TypedReference reference = __makeref(t); return *(System.IntPtr*)(&reference); } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static System.IntPtr AddressOfRef<T>(ref T t) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct { System.TypedReference reference = __makeref(t); System.TypedReference* pRef = &reference; return (System.IntPtr)pRef; //(&pRef) } /// <summary> /// Returns the unmanaged address of the given array. /// </summary> /// <param name="array"></param> /// <returns><see cref="IntPtr.Zero"/> if null, otherwise the address of the array</returns> [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOfByteArray(byte[] array) { if (array == null) return System.IntPtr.Zero; fixed (byte* ptr = array) return (System.IntPtr)(ptr - 2 * sizeof(void*)); //Todo staticaly determine size of void? } #endregion 

切换分配types:

 GCHandle handle = GCHandle.Alloc(a, GCHandleType.Normal); 

在.NET中获取任意对象的地址是不可能的,但如果更改源代码并使用mono,则可以完成。 请参阅说明: 获取.NET对象的内存地址(C#)