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);
    }
}
相关推荐
沐晓时光1 小时前
C语言入门,内存函数知识讲解
c语言·开发语言
David猪大卫7 小时前
【C++修炼】map 和 set 的使用
c语言·开发语言·数据结构·c++·经验分享·笔记·学习
用户3721574261357 小时前
C# 实现 Excel 单元格保护:锁定公式并允许编辑指定区域
c#·ai编程·编程语言
fengci.8 小时前
CTF2MISC中等部分
开发语言·前端·学习
xys_67810 小时前
JavaEE通关手册:初识Java
java·开发语言
ShineWinsu11 小时前
对于Qt:QTableWidget常见属性以及QTableWidgetItem类的解析
开发语言·c++·qt·gui·客户端·表格·qtablewidget
ShineWinsu12 小时前
对于Qt:QListWidget常见属性以及QListWidgetItem类的解析
开发语言·c++·qt·客户端·列表·qlistwidget·qlistwidgetitem
吴名氏.12 小时前
Java转AI Agent教程(第十二周)检索与切分
java·开发语言·人工智能·ai·ai agent
公子小六13 小时前
基于.NET的Windows窗体编程之WinForms数据持久化(1)
windows·microsoft·c#·.net·winforms
瑞雪兆丰年兮13 小时前
JavaWeb-day10-SpringBootWeb案例
java·开发语言·javaweb·web