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);
    }
}
相关推荐
新手unity自用笔记1 小时前
unity基于Socket的网络学习
网络·网络协议·学习·unity·c#·游戏引擎
橙橙笔记2 小时前
QT的安装
开发语言·qt·安装·软件
格林威2 小时前
C#图像像素放大:邻域平均、双线性插值实现像素放大的C#实现代码
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
兔兔兔兔13 小时前
记录C++ 8
开发语言·c++
名字还没想好☜3 小时前
Go 1.23 range-over-func 迭代器实战:自定义可迭代类型、提前退出与惰性求值
开发语言·后端·golang·go·迭代器
喵同志不止步于码农3 小时前
Java Caffeine 快速入门
java·开发语言·后端·并发·缓存一致性
2kπ4 小时前
QT开发笔记
开发语言·笔记·qt
青 春 记 忆4 小时前
零基础入门Python15|关联、聚合、索引与事务:订单数据库
开发语言·python·后端开发
江屿风4 小时前
【STM32基础篇】【嵌入式生态问题及历史追溯】流食般投喂
大数据·开发语言·人工智能·笔记·stm32·嵌入式硬件