I wrote one, shared it, can help someone:
[global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] public sealed class BitInfoAttribute : Attribute { byte length; public BitInfoAttribute(byte length) { this.length = length; } public byte Length { get { return length; } } } public abstract class BitField { public void parse<T>(T[] vals) { analysis().parse(this, ArrayConverter.convert<T, uint>(vals)); } public byte[] toArray() { return ArrayConverter.convert<uint, byte>(analysis().toArray(this)); } public T[] toArray<T>() { return ArrayConverter.convert<uint, T>(analysis().toArray(this)); } static Dictionary<Type, BitTypeInfo> bitInfoMap = new Dictionary<Type, BitTypeInfo>(); private BitTypeInfo analysis() { Type type = this.GetType(); if (!bitInfoMap.ContainsKey(type)) { List<BitInfo> infos = new List<BitInfo>(); byte dataIdx = 0, offset = 0; foreach (System.Reflection.FieldInfo f in type.GetFields()) { object[] attrs = f.GetCustomAttributes(typeof(BitInfoAttribute), false); if (attrs.Length == 1) { byte bitLen = ((BitInfoAttribute)attrs[0]).Length; if (offset + bitLen > 32) { dataIdx++; offset = 0; } infos.Add(new BitInfo(f, bitLen, dataIdx, offset)); offset += bitLen; } } bitInfoMap.Add(type, new BitTypeInfo(dataIdx + 1, infos.ToArray())); } return bitInfoMap[type]; } } class BitTypeInfo { public int dataLen { get; private set; } public BitInfo[] bitInfos { get; private set; } public BitTypeInfo(int _dataLen, BitInfo[] _bitInfos) { dataLen = _dataLen; bitInfos = _bitInfos; } public uint[] toArray<T>(T obj) { uint[] datas = new uint[dataLen]; foreach (BitInfo bif in bitInfos) { bif.encode(obj, datas); } return datas; } public void parse<T>(T obj, uint[] vals) { foreach (BitInfo bif in bitInfos) { bif.decode(obj, vals); } } } class BitInfo { private System.Reflection.FieldInfo field; private uint mask; private byte idx, offset, shiftA, shiftB; private bool isUnsigned = false; public BitInfo(System.Reflection.FieldInfo _field, byte _bitLen, byte _idx, byte _offset) { field = _field; mask = (uint)(((1 << _bitLen) - 1) << _offset); idx = _idx; offset = _offset; shiftA = (byte)(32 - _offset - _bitLen); shiftB = (byte)(32 - _bitLen); if (_field.FieldType == typeof(bool) || _field.FieldType == typeof(byte) || _field.FieldType == typeof(char) || _field.FieldType == typeof(uint) || _field.FieldType == typeof(ulong) || _field.FieldType == typeof(ushort)) { isUnsigned = true; } } public void encode(Object obj, uint[] datas) { if (isUnsigned) { uint val = (uint)Convert.ChangeType(field.GetValue(obj), typeof(uint)); datas[idx] |= ((uint)(val << offset) & mask); } else { int val = (int)Convert.ChangeType(field.GetValue(obj), typeof(int)); datas[idx] |= ((uint)(val << offset) & mask); } } public void decode(Object obj, uint[] datas) { if (isUnsigned) { field.SetValue(obj, Convert.ChangeType((((uint)(datas[idx] & mask)) << shiftA) >> shiftB, field.FieldType)); } else { field.SetValue(obj, Convert.ChangeType((((int)(datas[idx] & mask)) << shiftA) >> shiftB, field.FieldType)); } } } public class ArrayConverter { public static T[] convert<T>(uint[] val) { return convert<uint, T>(val); } public static T1[] convert<T0, T1>(T0[] val) { T1[] rt = null;
and use:
class MyTest01 : BitField { [BitInfo(3)] public bool d0; [BitInfo(3)] public short d1; [BitInfo(3)] public int d2; [BitInfo(3)] public int d3; [BitInfo(3)] public int d4; [BitInfo(3)] public int d5; public MyTest01(bool _d0, short _d1, int _d2, int _d3, int _d4, int _d5) { d0 = _d0; d1 = _d1; d2 = _d2; d3 = _d3; d4 = _d4; d5 = _d5; } public MyTest01(byte[] datas) { parse(datas); } public new string ToString() { return string.Format("d0: {0}, d1: {1}, d2: {2}, d3: {3}, d4: {4}, d5: {5} \r\nbinary => {6}", d0, d1, d2, d3, d4, d5, ArrayConverter.toBinary(toArray())); } }; class MyTest02 : BitField { [BitInfo(5)] public bool val0; [BitInfo(5)] public byte val1; [BitInfo(15)] public uint val2; [BitInfo(15)] public float val3; [BitInfo(15)] public int val4; [BitInfo(15)] public int val5; [BitInfo(15)] public int val6; public MyTest02(bool v0, byte v1, uint v2, float v3, int v4, int v5, int v6) { val0 = v0; val1 = v1; val2 = v2; val3 = v3; val4 = v4; val5 = v5; val6 = v6; } public MyTest02(byte[] datas) { parse(datas); } public new string ToString() { return string.Format("val0: {0}, val1: {1}, val2: {2}, val3: {3}, val4: {4}, val5: {5}, val6: {6}\r\nbinary => {7}", val0, val1, val2, val3, val4, val5, val6, ArrayConverter.toBinary(toArray())); } } public class MainClass { public static void Main(string[] args) { MyTest01 p = new MyTest01(false, 1, 2, 3, -1, -2); Debug.Log("P:: " + p.ToString()); MyTest01 p2 = new MyTest01(p.toArray()); Debug.Log("P2:: " + p2.ToString()); MyTest02 t = new MyTest02(true, 1, 12, -1.3f, 4, -5, 100); Debug.Log("t:: " + t.ToString()); MyTest02 t2 = new MyTest02(t.toArray()); Debug.Log("t:: " + t.ToString()); Console.Read(); return; } }