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);
    }
}
相关推荐
乌暮19 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习
2601_9622186119 小时前
C语言中三种库的编译和使用方法
开发语言·c++
传奇开心果编程19 小时前
中庸、有容、破执:仓颉编程语言的中华智慧结晶——三重哲学境界思辨
开发语言·华为·开源·软件工程
jimy119 小时前
派生类重写基类虚函数(二):override的作用
开发语言·c++
_upupup20 小时前
异常(C++)
java·开发语言·jvm
霸道流氓气质20 小时前
ComfyUI 图像生成工作流完全指南:从节点编排到Java生产级图像生产实战
java·开发语言·人工智能
ShyanZh21 小时前
【Python3基础】13-Python 常用设计模式
开发语言·python·设计模式
m0_3807438721 小时前
Qt侧边栏布局的实现示例
开发语言·c++
zh_xuan21 小时前
c++ 23 std::out_ptr用法
开发语言·c++23·out_ptr
陆卿之21 小时前
Java对接DeepSeek
java·开发语言·人工智能