在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#)
- ReaderWriterLock vs lock {}
- 我应该使用结构还是类来表示Lat / Lng坐标?
- int x = 10; x + = x–; 在.Net中 – 为什么?
- .NET LINQ查询语法与方法链
- Visual Studio 2015 RTM – debugging不起作用
- 你可以在代码中configurationlog4net而不是使用configuration文件?
- 删除常规数组的元素
- 什么更好:int.TryParse或尝试{int.Parse()} catch
- “Type not expected”,使用DataContractSerializer – 但它只是一个简单的类,没有有趣的东西?