c# 结构体 能不能直接封送检测

发布时间:2026/9/1 7:24:35
c# 结构体 能不能直接封送检测 #region Blittable 缓存检测器 public static class BlittableChecker { private static class CacheT where T : struct { public static readonly bool IsBlittable CheckInternal(); /// summary /// 可直接封送类型 /// /summary /// returns/returns private static bool CheckInternal() { T dummy default; GCHandle handle; try { handle GCHandle.Alloc(dummy, GCHandleType.Pinned); } catch (ArgumentException) { return false; } handle.Free(); return true; } } /// summary /// 判断值类型是否 Blittable每种 T 只校验一次全局缓存 /// /summary public static bool IsBlittableT() where T : struct { return CacheT.IsBlittable; } } #endregion #region 泛型数组锁定工具类 public static unsafe class BufferLockHelper { /// summary /// 锁定结构体数组回调内瞬时获取指针fixed同步使用不可缓存指针 /// /summary /// typeparam nameTblittable struct/typeparam /// param nameimgData目标数组/param /// param nameact回调指针元素个数总字节大小/param public static void LockStructArrayT(T[] imgData, ActionIntPtr, int, int act) where T : struct { if (imgData null) throw new ArgumentNullException(nameof(imgData)); if (imgData.Length 0) return; if (!BlittableChecker.IsBlittableT()) { throw new NotSupportedException( $结构体 {typeof(T).FullName} 不是 Blittable禁止将 fixed 裸指针传递给非托管代码); } int elemSize Marshal.SizeOf(typeof(T)); int totalBytes elemSize * imgData.Length; fixed (void* ptr imgData) { act(new IntPtr(ptr), imgData.Length, totalBytes); } } } #endregion不能封送public struct BadStructWithBool { public int X; public bool Valid; }第一次改造可以封送但是不能Pinned// 这样改【无效】仍然不能Pinned、不能通过 BlittableChecker [StructLayout(LayoutKind.Sequential, Pack 1)] public struct StillBad { public int X; [MarshalAs(UnmanagedType.U1)] public bool Valid; // 字段本质仍是 boolCLR判定为non-blittable }第二次改造后 可以封送[StructLayout(LayoutKind.Sequential, Pack 1)] public struct GoodStructWithBool { public int X; private byte _valid; // 底层用 byteblittable // 对外 bool 访问器不影响内存布局 public bool Valid { get _valid ! 0; set _valid (byte)(value ? 1 : 0); } }比较简单的检查是不是Blittable , C# 里的 blittable可直通类型指托管内存布局和非托管内存布局完全一致的类型跨边界传递时无需任何转换marshaling可以直接零拷贝搬运内存。对追求无 GC、unsafe 指针的场景这是性能关键。unsafe { var t1 Marshal.SizeOf(typeof(S7.OrbitCacheIndexBB)); var t2 sizeof(S7.OrbitCacheIndexBB); var t3 t1 t2; }