能否无需编写大型switch语句获取装箱非托管值类型的指针?
获取装箱非托管值类型指针的无switch方案
当然可以不用编写大型switch语句实现需求,下面提供两种高效实现方式,均需项目启用不安全代码(在项目设置中开启"允许不安全代码"选项):
方案1:直接获取堆上装箱值的指针
该方法无需拆箱复制,直接指向堆中装箱值的内存区域,只要对象未被GC回收,指针就有效:
using System.Runtime.CompilerServices; object val = 123L; // 示例:装箱的long类型 void* GetBoxedHeapPointer(object boxedValue) { // 获取装箱对象的原始指针 IntPtr objBasePtr = Unsafe.As<object, IntPtr>(ref boxedValue); // 偏移对象头(同步块索引 + 方法表指针),定位到值的起始地址 return (void*)(objBasePtr + IntPtr.Size * 2); } // 使用示例 void* ptr = GetBoxedHeapPointer(val); DoStuffWithPointer(ptr);
方案2:获取栈上值的指针(与原switch逻辑行为一致)
如果你需要和原代码一样,指针指向栈上的局部变量(接受函数返回后指针失效的情况),可以通过动态分配栈内存并复制装箱值实现:
using System; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; object val = (byte)0xAB; // 示例:装箱的byte类型 void* GetBoxedStackPointer(object boxedValue) { Type valueType = boxedValue.GetType(); int valueSize = Marshal.SizeOf(valueType); // 在栈上分配对应大小的内存缓冲区 void* stackBuffer = Unsafe.AllocateStack(valueSize); // 获取堆上装箱值的指针 void* heapValuePtr = GetBoxedHeapPointer(boxedValue); // 将堆上的值复制到栈缓冲区 Unsafe.Copy(stackBuffer, heapValuePtr, (uint)valueSize); return stackBuffer; } // 使用示例 void* ptr = GetBoxedStackPointer(val); DoStuffWithPointer(ptr);
注意事项
- 两种方法均依赖
System.Runtime.CompilerServices.Unsafe类,.NET Core 2.0+/.NET 5+默认包含该类。 - 方案1的指针依赖装箱对象的生命周期,若对象被GC回收,指针会失效;方案2的指针仅在当前栈帧有效,函数返回后即失效,符合你的预期。
内容的提问来源于stack exchange,提问作者kaalus
相关产品推荐
相关产品推荐

