You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何打包bit fields?寻求非反射实现16位PESHeader方案

嘿,我完全懂你的需求——想用单个16位变量p来打包PESHeader的位域,还不想用反射(毕竟反射在这种场景下不仅慢,代码还乱糟糟的)。下面给你几个比反射高效得多的实现方案,都是实际项目里常用的:

方案1:手动位运算封装(极致性能)

这是性能最优的方案,完全手动控制位掩码,没有任何额外开销,代码逻辑清晰可控。你可以把底层存储封装在结构体或类里,通过属性的get/set来实现位域的读写:

public struct PESHeader
{
    private ushort _p; // 核心16位存储变量

    // 示例:Sync位(1位,最高位,掩码0x8000)
    public bool SyncBit
    {
        get => (_p & 0x8000) != 0;
        set
        {
            if (value)
                _p |= 0x8000;
            else
                _p &= (ushort)~0x8000;
        }
    }

    // 示例:传输错误指示位(1位,掩码0x4000)
    public bool TransportErrorIndicator
    {
        get => (_p & 0x4000) != 0;
        set
        {
            if (value)
                _p |= 0x4000;
            else
                _p &= (ushort)~0x4000;
        }
    }

    // 示例:PID字段(12位,低12位,掩码0x0FFF)
    public ushort PID
    {
        get => (ushort)(_p & 0x0FFF);
        set => _p = (ushort)((_p & 0xF000) | (value & 0x0FFF));
    }

    // 获取原始16位值
    public ushort RawValue => _p;

    // 从原始值初始化
    public PESHeader(ushort rawValue) => _p = rawValue;
}

优势:没有依赖,性能拉满,每个位域的操作都完全透明,适合对性能要求高的实时场景。

方案2:使用.NET自带的BitVector16(简洁易维护)

如果你不想手动写一堆位掩码,可以用System.Collections.Specialized里的BitVector16——它专门为16位位域设计,封装了单个位的读写逻辑,代码会更简洁:

using System.Collections.Specialized;

public class PESHeader
{
    private readonly BitVector16 _bitVector;

    // 自动生成单个位的掩码
    private static readonly int SyncBitMask = BitVector16.CreateMask();
    private static readonly int TransportErrorIndicatorMask = BitVector16.CreateMask(SyncBitMask);
    private static readonly int PayloadStartIndicatorMask = BitVector16.CreateMask(TransportErrorIndicatorMask);
    
    // 多比特字段还是需要手动定义掩码
    private const ushort PIDMask = 0x0FFF;

    public PESHeader(ushort rawValue)
    {
        _bitVector = new BitVector16(rawValue);
    }

    public bool SyncBit
    {
        get => _bitVector[SyncBitMask];
        set => _bitVector[SyncBitMask] = value;
    }

    public bool TransportErrorIndicator
    {
        get => _bitVector[TransportErrorIndicatorMask];
        set => _bitVector[TransportErrorIndicatorMask] = value;
    }

    public ushort PID
    {
        get => (ushort)(_bitVector.Data & PIDMask);
        set => _bitVector.Data = (ushort)((_bitVector.Data & ~PIDMask) | (value & PIDMask));
    }

    public ushort RawValue => _bitVector.Data;
}

优势:单个位的操作不用自己写掩码,代码更简洁,可读性更好,性能比反射强N倍,只是比手动位运算略逊一筹。

方案3:StructLayout内存重叠(适合非托管交互)

如果你的PESHeader需要和C/C++等非托管代码交互,或者直接操作内存,可以用StructLayout和FieldOffset实现内存重叠,类似C语言的位域写法:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit, Size = 2)] // 强制结构体大小为2字节(16位)
public struct PESHeader
{
    [FieldOffset(0)]
    public ushort RawValue; // 整个16位存储变量

    [FieldOffset(0)]
    public byte HighByte; // 高8位字节
    [FieldOffset(1)]
    public byte LowByte; // 低8位字节

    // Sync位(高字节的第7位)
    public bool SyncBit
    {
        get => (HighByte & 0x80) != 0;
        set
        {
            if (value)
                HighByte |= 0x80;
            else
                HighByte &= 0x7F;
        }
    }

    // 传输错误指示位(高字节的第6位)
    public bool TransportErrorIndicator
    {
        get => (HighByte & 0x40) != 0;
        set
        {
            if (value)
                HighByte |= 0x40;
            else
                HighByte &= 0xBF;
        }
    }

    // PID字段(高字节低4位 + 低字节全部8位,共12位)
    public ushort PID
    {
        get => (ushort)(((HighByte & 0x0F) << 8) | LowByte);
        set
        {
            HighByte = (byte)((HighByte & 0xF0) | ((value >> 8) & 0x0F));
            LowByte = (byte)(value & 0xFF);
        }
    }
}

优势:可以直接和非托管代码的结构体映射,内存布局完全可控,性能和手动位运算差不多。


这三个方案都完全避开了反射,性能和可维护性都比反射好太多。根据你的场景选就行:追求最快速度就用手动位运算;想少写重复代码就用BitVector16;如果要和非托管代码交互,StructLayout的方式最适配。

内容的提问来源于stack exchange,提问作者electro103

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:22:20