PropertyBitPack
This library, PropertyBitPack, is a Roslyn source generator that simplifies the process of defining and managing bit-packed properties in C#. It allows developers to decorate properties with custom attributes to automatically generate efficient bit manipulation code.
Install / Use
/learn @Asaicraft/PropertyBitPackREADME
PropertyBitPack
PropertyBitPack is a Roslyn source generator that simplifies defining and managing bit-packed properties in C#. It allows developers to decorate properties with custom attributes to automatically generate efficient bit manipulation code.
Table of Contents
- Installation
- Usage
- Define Bit-Packed Boolean Properties
- Define Bit-Packed Properties with Mixed Types
- Define Bit-Packed Properties with Custom Bit Sizes
- Generate Custom Field Names
- Define Bit-Packed Properties with Already Defined Fields
- ExtendedBitFieldAttribute
- Define Read-Only Bit-Packed Properties
- ReadOnlyExtendedBitField
- BitFieldUtils Overview
Installation
PropertyBitPack is available as a NuGet package. You can install it using the following command:
dotnet add package PropertyBitPack
Usage
Define Bit-Packed Boolean Properties
By default, boolean properties are stored using at least 1 byte of memory. To reduce memory usage, you can use the BitFieldAttribute to pack multiple bool properties into a single byte.
The following example demonstrates how to define bit-packed boolean properties using the BitFieldAttribute:
using PropertyBitPack;
namespace SomeNamespace;
public partial class BitPackedBools
{
[BitField]
public partial bool Bool1 { get; set; }
[BitField]
public partial bool Bool2 { get; set; }
[BitField]
public partial bool Bool3 { get; set; }
[BitField]
public partial bool Bool4 { get; set; }
}
This will generate the following code:
partial class BitPackedBools
{
private byte _Bool1__Bool2__Bool3__Bool4__;
public partial bool Bool1
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__ >> 0) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 0)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 0)));
}
}
public partial bool Bool2
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__ >> 1) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 1)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 1)));
}
}
public partial bool Bool3
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__ >> 2) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 2)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 2)));
}
}
public partial bool Bool4
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__ >> 3) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__ = (byte)(value ? ((this._Bool1__Bool2__Bool3__Bool4__) | (((1 << 1) - 1) << 3)) : (this._Bool1__Bool2__Bool3__Bool4__ & ~(((1 << 1) - 1) << 3)));
}
}
}
Define Bit-Packed Properties with Mixed Types
The BitFieldAttribute can also be used to pack multiple properties of different types into a single field. The following example demonstrates how to define bit-packed properties for booleans and a byte using the BitFieldAttribute:
using PropertyBitPack;
namespace SomeNamespace;
public partial class BitPackedBools
{
[BitField]
public partial bool Bool1 { get; set; }
[BitField]
public partial bool Bool2 { get; set; }
[BitField]
public partial bool Bool3 { get; set; }
[BitField]
public partial bool Bool4 { get; set; }
[BitField]
public partial byte Byte1 { get; set; }
}
This will generate the following code:
partial class BitPackedBools
{
private ushort _Bool1__Bool2__Bool3__Bool4__Byte1__;
public partial bool Bool1
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 0) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 0)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 0)));
}
}
public partial bool Bool2
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 1) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 1)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 1)));
}
}
public partial bool Bool3
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 2) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 2)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 2)));
}
}
public partial bool Bool4
{
get
{
return ((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 3) & (1)) == 1;
}
set
{
this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)(value ? ((this._Bool1__Bool2__Bool3__Bool4__Byte1__) | (((1 << 1) - 1) << 3)) : (this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 1) - 1) << 3)));
}
}
public partial byte Byte1
{
get
{
return (byte)((this._Bool1__Bool2__Bool3__Bool4__Byte1__ >> 4) & ((1 << 8) - 1));
}
set
{
const ushort maxValue_ = (1 << 8) - 1;
var clamped_ = global::System.Math.Min((ushort)(value), maxValue_);
this._Bool1__Bool2__Bool3__Bool4__Byte1__ = (ushort)((this._Bool1__Bool2__Bool3__Bool4__Byte1__ & ~(((1 << 8) - 1) << 4)) | ((clamped_ & ((1 << 8) - 1)) << 4));
}
}
}
As you can see, the BitFieldAttribute can pack multiple properties of different types into a single field. In this example, 1 + 1 + 1 + 1 + 8 = 12 bits are packed into a single ushort field.
Define Bit-Packed Properties with Custom Bit Sizes
The BitFieldAttribute can also be used to pack properties with custom bit sizes. The following example demonstrates how to define bit-packed properties with custom bit sizes:
internal sealed partial record RecordExample
{
[BitField(BitsCount = 4)]
public partial byte Property1 { get; init; }
[BitField(BitsCount = 11)]
public partial int Property2 { get; init; }
}
This will generate the following code:
partial record RecordExample
{
private ushort _Property1__Property2__;
public partial byte Property1
{
get
{
return (byte)((this._Property1__Property2__ >> 0) & ((1 << 4) - 1));
}
init
{
const ushort maxValue_ = (1 << 4) - 1;
var clamped_ = global::System.Math.Min((ushort)(value), maxValue_);
this._Property1__Property2__ = (ushort)((this._Property1__Property2__ & ~(((1 << 4) - 1) << 0)) | ((clamped_ & ((1 << 4) - 1)) << 0));
}
}
public partial int Property2
{
get
{
return (int)((this._Property1__Property2__ >> 4) & ((1 << 11) - 1));
}
init
{
const ushort maxValue_ = (1 << 11) - 1;
var clamped_ = global::System.Math.Min((ushort)(value), maxValue_);
this._Property1__Property2__ = (ushort)((this._Property1__Property2__ & ~(((1 << 11) - 1) << 4)) | ((clamped_ & ((1 << 11) - 1)) << 4));
}
}
}
Generate Custom Field Names
You can also specify a custom field name using the FieldName property of the BitFieldAttribute. The following example demonstrates how to define bit-packed properties with custom field names:
internal sealed partial class NamedFieldExample
{
[BitField(FieldName = "_another", BitsCount = 9)]
public partial short Short1 { get; set; }
[BitField(FieldName = "_another", BitsCount = 9)]
public partial short Short2 { get; set; }
}
This will generate the following code:
partial class NamedFieldExample
{
private uint _another;
public partial short Short1
{
get
{
return (short)((this._another >> 0) & ((1U << 9) - 1));
}
set
{
const uint maxValue_ = (1U << 9) - 1;
var clamped_ = global::System.Math.Min((uint)(value), maxValue_);
this._another = (uint)((this._another & ~(((1U << 9) - 1) << 0)) | ((clamped_ & ((1U << 9) - 1)) << 0));
}
}
public partial short Short2
{
get
{
return (short)((this._another >> 9) & ((1U << 9) - 1));
}
set
{
const uint maxValue_ = (1U << 9) - 1;
var clamped_ = global::System.Math.Min((uint)(value), maxValue_);
this._another = (uint)((this._anot
Related Skills
node-connect
354.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
112.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
354.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
354.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
