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);
    }
}
相关推荐
djarmy4 小时前
MAIN.c(1): warning C318: can’t open file ‘STC8G.H’ 报错 解决 分析
c语言·开发语言·mongodb
HEJOO94 小时前
深入理解 Java volatile 关键字:原理、用法与常见误区
java·开发语言·spring
曹牧4 小时前
Java:no content to map due to end of input
java·开发语言
梦梦代码精4 小时前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
隔窗听雨眠4 小时前
记一次SQL Server数据库性能分析:从CPU100%到单配置修复的完整诊断
开发语言·数据库·php
David猪大卫5 小时前
【C++修炼】智能指针使用及原理
开发语言·c++·经验分享·笔记·学习·考研·面试
charlie1145141915 小时前
现代Qt开发之图像处理进阶:像素操作与格式转换
开发语言·图像处理·qt
李永奉5 小时前
中科蓝讯SDK开发-BT893x 面条耳机连接vivo手机后连接APP端,最后手机端设置页面手动断开蓝牙连接,此时耳机端假断开
c语言·开发语言·嵌入式硬件·物联网·智能手机·电脑
秦老师Q6 小时前
php零基础入门到实战,从语法到框架,一篇搞定
开发语言·php
驭渊的小故事6 小时前
多线程02
java·开发语言·jvm