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); // 0x01020304
Byte 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); // 1000
ReadOnlySpan<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); // 10
IReadOnlyList<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, 0xFF
ReadOnlyMemory<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); // 0x12345678
Stream
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); // 0x0102
UInt16Extensions 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