Reading and Writing Primitive Values
The library provides extension methods for reading and writing multi-byte primitive values from a variety of C# byte container types. All methods use a consistent naming convention and support configurable byte ordering via the Endian enum.
Supported Types
The following primitive types can be read and written:
| Method Suffix | .NET Type | Size |
|---|---|---|
Int16 | short | 2 bytes |
UInt16 | ushort | 2 bytes |
UInt24 | UInt24 | 3 bytes |
Int32 | int | 4 bytes |
UInt32 | uint | 4 bytes |
Int64 | long | 8 bytes |
UInt64 | ulong | 8 bytes |
Endianness
All multi-byte methods accept an optional Endian parameter. The default is Endian.Little (least significant byte first). Pass Endian.Big to use big-endian (most significant byte first) byte ordering.
byte[] bytes = [0x01, 0x02, 0x03, 0x04];
int littleEndian = bytes.GetInt32(0); // 0x04030201
int bigEndian = bytes.GetInt32(0, Endian.Big); // 0x01020304Byte Containers
byte[] and Span<byte>
ByteArrayExtensions and ByteSpanExtensions support both reading (Get*) and writing (Set*). All methods take a zero-based index indicating where in the array or span to read from or write to.
byte[] data = new byte[8];
data.SetInt32(0, 42);
data.SetUInt16(4, 1000, Endian.Big);
int value = data.GetInt32(0); // 42
ushort word = data.GetUInt16(4, Endian.Big); // 1000ReadOnlySpan<byte>
ByteReadOnlySpanExtensions supports reading only. The index parameter specifies the start position.
ReadOnlySpan<byte> span = stackalloc byte[] { 0xFF, 0x00, 0x00, 0x00 };
int value = span.GetInt32(0); // -1 (little-endian signed int32)IList<byte> and List<byte>
ByteIListExtensions and ByteListExtensions support both Get* and Set* methods. List<byte> has optimised overloads that avoid virtual dispatch.
var list = new List<byte> { 0x0A, 0x00, 0x00, 0x00 };
int value = list.GetInt32(0); // 10IReadOnlyList<byte>
ByteIReadOnlyListExtensions supports reading only. It also provides a CopyTo method for copying the entire list into a Span<byte>.
IReadOnlyList<byte> source = new List<byte> { 1, 2, 3, 4 };
uint value = source.GetUInt32(0);
Span<byte> destination = stackalloc byte[4];
source.CopyTo(destination);ICollection<byte>
ByteICollectionExtensions provides Add* methods that append the bytes of a value to the collection in the specified byte order. These are useful for building up byte sequences.
var buffer = new List<byte>();
buffer.AddUInt16(0x0102); // appends 0x02, 0x01 (little-endian)
buffer.AddUInt16(0x0102, Endian.Big); // appends 0x01, 0x02 (big-endian)
buffer.AddInt32(-1); // appends 0xFF, 0xFF, 0xFF, 0xFFReadOnlyMemory<byte>
ReadOnlyMemoryExtensions supports reading only, with the same Get* methods and index parameter as other read-only containers.
ReadOnlyMemory<byte> memory = new byte[] { 0x78, 0x56, 0x34, 0x12 };
int value = memory.GetInt32(0); // 0x12345678Stream
StreamExtensions provides Read*OrThrow and Write* methods for sequential reading and writing. Read methods throw EndOfStreamException if the stream ends before enough bytes are available. All methods have asynchronous counterparts suffixed with Async.
using var stream = new MemoryStream();
stream.WriteInt32(42);
stream.WriteUInt16(1000, Endian.Big);
stream.Position = 0;
int a = stream.ReadInt32OrThrow();
ushort b = stream.ReadUInt16OrThrow(Endian.Big);Asynchronous versions follow the same pattern:
await stream.WriteInt32Async(42);
int value = await stream.ReadInt32OrThrowAsync();Additional helper methods are available for reading raw bytes:
ReadByteOrThrow()reads a single byte or throwsEndOfStreamException.ReadExactly(length)reads a specific number of bytes or throwsEndOfStreamException.ReadAllBytes()reads all remaining bytes into a new array.
Composing Values from Individual Bytes
EndianExtensions provides methods for composing values from individual bytes when working byte-by-byte:
byte b0 = 0x01, b1 = 0x02;
ushort value = Endian.Little.ToUInt16(b0, b1); // 0x0201
ushort big = Endian.Big.ToUInt16(b0, b1); // 0x0102UInt16Extensions provides ToBytes() for decomposing a ushort into its most and least significant bytes, and ByteByteTupleExtensions provides ToUInt16() for the reverse:
ushort value = 0x1234;
(byte msb, byte lsb) = value.ToBytes(); // msb = 0x12, lsb = 0x34
ushort reconstructed = (msb, lsb).ToUInt16(); // 0x1234