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

cs 复制代码
    #region Blittable 缓存检测器
    public static class BlittableChecker
    {
        private static class Cache<T> 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 IsBlittable<T>() where T : struct
        {
            return Cache<T>.IsBlittable;
        }
    }
    #endregion

    #region 泛型数组锁定工具类
    public static unsafe class BufferLockHelper
    {
        /// <summary>
        /// 锁定结构体数组,回调内瞬时获取指针(fixed,同步使用,不可缓存指针)
        /// </summary>
        /// <typeparam name="T">blittable struct</typeparam>
        /// <param name="imgData">目标数组</param>
        /// <param name="act">回调:指针,元素个数,总字节大小</param>
        public static void LockStructArray<T>(T[] imgData, Action<IntPtr, int, int> act)
            where T : struct
        {
            if (imgData == null)
                throw new ArgumentNullException(nameof(imgData));

            if (imgData.Length == 0)
                return;

            if (!BlittableChecker.IsBlittable<T>())
            {
                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

不能封送

cs 复制代码
public struct BadStructWithBool
{
public int X;
public bool Valid;
}

第一次改造,可以封送,但是不能Pinned

cs 复制代码
// 这样改【无效】,仍然不能Pinned、不能通过 BlittableChecker
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct StillBad
{
    public int X;
    [MarshalAs(UnmanagedType.U1)]
    public bool Valid; // 字段本质仍是 bool,CLR判定为non-blittable
}

第二次改造后 ,可以封送

cs 复制代码
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GoodStructWithBool
{
    public int X;
    private byte _valid; // 底层用 byte(blittable)

    // 对外 bool 访问器,不影响内存布局
    public bool Valid
    {
        get => _valid != 0;
        set => _valid = (byte)(value ? 1 : 0);
    }
}
相关推荐
想做小南娘,发现自己是女生喵6 分钟前
QT项目实战第一周(嵌入式)
开发语言·qt
学逆向的13 分钟前
C 可变量参数
c语言·开发语言·网络安全
andyweike14 分钟前
kotlin dsl library工程怎么配置
android·开发语言·kotlin
huaweichenai20 分钟前
php搭建mcp服务
开发语言·php·ai编程
估值探索者33 分钟前
【Python量化技术指标实战 02】MACD金叉也分强弱?手工算一次 DIF/DEA 就懂了
java·开发语言·python·股票数据·股票数据api接口
讳疾忌医丶34 分钟前
编译器眼中的 C++ 循环:从指针别名、IEEE 754 结合律到 SIMD 语义证明
开发语言·c++
重生六道1 小时前
B站视频时长统计:一段JS脚本搞定分P/合集总时长(附倍速计算)
开发语言·javascript·音视频
XiYang-DING1 小时前
P5528.带过期时间的 LRU 缓存
java·开发语言·缓存
小徐不徐说1 小时前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
zhangx1234_2 小时前
javaEE 多线程4
java·开发语言