Salar.Bois.CodeGen
4.0.0
dotnet add package Salar.Bois.CodeGen --version 4.0.0
NuGet\Install-Package Salar.Bois.CodeGen -Version 4.0.0
<PackageReference Include="Salar.Bois.CodeGen" Version="4.0.0" />
<PackageVersion Include="Salar.Bois.CodeGen" Version="4.0.0" />
<PackageReference Include="Salar.Bois.CodeGen" />
paket add Salar.Bois.CodeGen --version 4.0.0
#r "nuget: Salar.Bois.CodeGen, 4.0.0"
#:package Salar.Bois.CodeGen@4.0.0
#addin nuget:?package=Salar.Bois.CodeGen&version=4.0.0
#tool nuget:?package=Salar.Bois.CodeGen&version=4.0.0
Salar.Bois is the most compact, extermly fast binary serializer for .Net Standard, .NET Code and .NET Framework.
- No compression is done, the high compact ratio is the result of Bois format.
- No configuration.
- No change to your classes.
- Compression is provided as a seperate package.
Why Salar.Bois?
- Because payload size matters. Bois serializer generates the smallest payload size.
- Because speed matters. Both serialization and deserialization are extremely fast.
- Easy to use,
Serialize<T>andDeserialize<T>are all you need. - No configuration required. No separate schema required.
NuGet Packages
PM> Install-Package Salar.Bois.CodeGen
PM> Install-Package Salar.Bois
LZ4 Compression wrapper package
PM> Install-Package Salar.Bois.LZ4
Minimum frameworks supported are .NET Framework 4.8 , .NET 6.0 and up to latest .NET 10.0
Getting Started with Source generator
The Salar.Bois.CodeGen package provides the source code generator version of Bois. Instead of using the BoisSerializer class at runtime, you declare a static partial class that hosts the read and write methods as static partial methods. The generator creates the method body during compilation.
To use it, add the Salar.Bois.CodeGen package to your project and create a static partial class to host your serializer methods. Mark read methods with [BoisReader] and write methods with [BoisWriter].
The serializer class must be partial, and every generated method must also be partial. This is how the compiler connects your method declarations with the generated implementations. If the class or methods are not partial, source generation cannot complete the methods.
Important: source generated partial methods with accessibility require C# 9.0 or later. If your project uses an older C# language version, set <LangVersion>9.0</LangVersion> or a newer version in your project file.
You can then call these methods like normal methods. There is no need to create a BoisSerializer instance for this generated path.
using Salar.BinaryBuffers;
using Salar.Bois.CodeGen;
using System;
using System.IO;
using System.Text;
public static partial class CustomerOrderSerializer
{
// ... other signatures ...
[BoisReader]
public static partial CustomerOrder? ReadCustomerOrder(Stream source);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder? order, Stream output);
[BoisReader]
public static partial CustomerOrder? ReadCustomerOrder(byte[] buffer, int position, int length);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder? order, byte[] buffer, int position, int length);
// ... other signatures ...
}
Sample usage:
using (var file = new FileStream("output.data", FileMode.Create))
{
CustomerOrderSerializer.WriteCustomerOrder(order, file);
}
using (var file = new FileStream("output.data", FileMode.Open))
{
var order = CustomerOrderSerializer.ReadCustomerOrder(file);
}
You can also use an existing byte array buffer. This is useful when your application already owns the memory and you want to avoid creating an extra stream.
var buffer = new byte[4096];
CustomerOrderSerializer.WriteCustomerOrder(order, buffer, 0, buffer.Length);
var restoredOrder = CustomerOrderSerializer.ReadCustomerOrder(buffer, 0, buffer.Length);
Generated methods use BoisCodeGen.DefaultEncoding when an Encoding argument is not supplied. It defaults to UTF-8 and can be configured during application startup.
BoisCodeGen.DefaultEncoding = Encoding.UTF8;
The generated methods support stream based input and output. They also support buffer reader and buffer writer overloads, byte array overloads, array segment overloads for reading, and byte array overloads with position and length when you want to work directly with an existing buffer.
Method code generation is good for performance because the serializer code is created at compile time. There is no first use cost for building serializers at runtime, and there is no reflection based initialization step before the first serialization call. This also makes the package suitable for NativeAOT, where runtime code generation is not available.
Supported method signatures:
using Salar.BinaryBuffers;
using Salar.Bois.CodeGen;
using System;
using System.IO;
using System.Text;
public static partial class CustomerOrderSerializer
{
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(Stream source);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(Stream source, Encoding encoding);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(BufferReaderBase reader);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(BufferReaderBase reader, Encoding encoding);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(byte[] buffer);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(byte[] buffer, Encoding encoding);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(ArraySegment<byte> bytes);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(ArraySegment<byte> bytes, Encoding encoding);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrderIn(in ArraySegment<byte> bytes);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrderIn(in ArraySegment<byte> bytes, Encoding encoding);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(byte[] buffer, int position, int length);
[BoisReader]
public static partial CustomerOrder ReadCustomerOrder(byte[] buffer, int position, int length, Encoding encoding);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder order, Stream output);
[BoisWriter]
public static partial void WriteCustomerOrder(Stream output, CustomerOrder order);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder order, Stream output, Encoding encoding);
[BoisWriter]
public static partial void WriteCustomerOrder(Stream output, CustomerOrder order, Encoding encoding);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder order, BufferWriterBase writer);
[BoisWriter]
public static partial void WriteCustomerOrder(BufferWriterBase writer, CustomerOrder order);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder order, BufferWriterBase writer, Encoding encoding);
[BoisWriter]
public static partial void WriteCustomerOrder(BufferWriterBase writer, CustomerOrder order, Encoding encoding);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder order, byte[] buffer, int position, int length);
[BoisWriter]
public static partial void WriteCustomerOrder(byte[] buffer, int position, int length, CustomerOrder order);
[BoisWriter]
public static partial void WriteCustomerOrder(CustomerOrder order, byte[] buffer, int position, int length, Encoding encoding);
[BoisWriter]
public static partial void WriteCustomerOrder(byte[] buffer, int position, int length, CustomerOrder order, Encoding encoding);
}
Getting Started with dynamic BoisSerializer
It is easy to use , just add the package to your project and voila, you can now use it.
All you need to do is to call Serialize method.
BoisSerializer.Initialize<Person>();
var boisSerializer = new BoisSerializer();
using (var mem = new MemoryStream())
{
boisSerializer.Serialize(personInstance, mem);
return mem.ToArray();
}
Note: Calling BoisSerializer.Initialize is not required at all, but if the performance of application is important to you, it is better to do it at the begining of your application.
Here is the complete example:
public class Project
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ProjectUrl { get; set; }
public Version Version { get; set; }
}
class Program
{
static void Main()
{
// Initialize is optional, but recommended for better performance
BoisSerializer.Initialize<Project>();
var projectInstance = new Project()
{
ID = 1,
Name = "Salar.Bois",
ProjectUrl = "https://github.com/salarcode/Bois",
Version = new Version(3, 0, 0, 0),
Description = "Salar.Bois is a compact, fast and powerful binary serializer for .NET Framework."
};
var boisSerializer = new BoisSerializer();
using (var file = new FileStream("output.data", FileMode.Create))
{
boisSerializer.Serialize(projectInstance, file);
}
// All done.
// ...
// if you want to have more compression using LZ4 wrapper
var boisLz4Serializer = new BoisLz4Serializer();
using (var file = new FileStream("output-compressed.data", FileMode.Create))
{
boisLz4Serializer.Pickle(projectInstance, file);
}
}
}
How to deserialize an object:
var boisSerializer = new BoisSerializer();
return boisSerializer.Deserialize<Project>(dataStream);
// and the compressed data
var boisLz4Serializer = new BoisLz4Serializer();
return boisLz4Serializer.Unpickle<Project>(dataStream);
Defining objects
Nothing special is really required. Just these small easy rules.
- Having parameter-less public constructor.
- Collections/Lists should be generic and implement one of ICollection<>, IList<> or IDictionary<>
Compression
The BoisLz4Serializer class is in a separate package called Salar.Bois.LZ4. It is provided for anyone looking for more compact serialization. To use it just create a new instance of BoisLz4Serializer and to serialize and compress the objects call Pickle and to deserialize and uncompress call Unpickle.
Please note that BoisLz4Serializer -for now- is implemented as a wrapper around LZ4.
Bois Format
If you are interested to know how Salar.Bois has gain this amazing compact format check out its Bois format wiki page.
Benchmarks
The benchmarks sourcecode is available. Every elapsed time is calculated for 5000 iteration (v3.0).
Please note that in these tests no configuration required for Bois versus attributes required for Avro, Zero, MsPack and ProtoZBuff. Also Zero required the properties to be virtual.
-Serialization against: ArrayTypes with small data
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 58 | 6 ms | 5 ms | Binary | |
| Salar.Bois.LZ4 | 59 | 25 ms | 6 ms | Binary | |
| Microsoft.Avro | 87 | 9 ms | 10 ms | Binary | |
| MessagePack | 127 | 4 ms | 4 ms | Binary | |
| MessagePackLZ4 | 125 | 18 ms | 5 ms | Binary | |
| protobuf-net | 92 | 7 ms | 12 ms | Binary | |
| BinaryFormatter | 458 | 59 ms | 48 ms | Binary | |
| ZeroFormatter | 153 | 3 ms | 1 ms | Binary |
-Serialization against: ArrayTypes with big data
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 1400 | 70 ms | 73 ms | Binary | |
| Salar.Bois.LZ4 | 1342 | 117 ms | 75 ms | Binary | |
| Microsoft.Avro | 1709 | 89 ms | 119 ms | Binary | |
| MessagePack | 1951 | 19 ms | 28 ms | Binary | |
| MessagePackLZ4 | 1593 | 57 ms | 41 ms | Binary | |
| protobuf-net | 2161 | 58 ms | 79 ms | Binary | |
| BinaryFormatter | 2641 | 52 ms | 50 ms | Binary | |
| ZeroFormatter | 2336 | 11 ms | 1 ms | Binary |
-Serialization against: PrimitiveTypes with small data
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 74 | 3 ms | 4 ms | Binary | |
| Salar.Bois.LZ4 | 75 | 19 ms | 5 ms | Binary | |
| Microsoft.Avro | 77 | 4 ms | 3 ms | Binary | |
| MessagePack | 161 | 7 ms | 3 ms | Binary | |
| MessagePackLZ4 | 173 | 22 ms | 3 ms | Binary | |
| protobuf-net | 91 | 6 ms | 7 ms | Binary | |
| BinaryFormatter | 671 | 72 ms | 79 ms | Binary | |
| ZeroFormatter | 134 | 7 ms | 0 ms | Binary |
-Serialization against: ComplexCollections with small data
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 82 | 14 ms | 23 ms | Binary | |
| Salar.Bois.LZ4 | 81 | 30 ms | 24 ms | Binary | |
| Microsoft.Avro | - | - | - | Binary | Error |
| MessagePack | 171 | 27 ms | 19 ms | Binary | |
| MessagePackLZ4 | 153 | 42 ms | 21 ms | Binary | |
| protobuf-net | 150 | 17 ms | 34 ms | Binary | |
| BinaryFormatter | 10852 | 636 ms | 612 ms | Binary | |
| ZeroFormatter | - | - | - | Binary | Not supported |
-Serialization against: ComplexCollections with big data
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 10414 | 356 ms | 411 ms | Binary | |
| Salar.Bois.LZ4 | 7628 | 837 ms | 483 ms | Binary | |
| Microsoft.Avro | - | - | - | Binary | Error |
| MessagePack | 11013 | 796 ms | 301 ms | Binary | |
| MessagePackLZ4 | 7636 | 28 ms | 390 ms | Binary | |
| protobuf-net | 14865 | 7 ms | 265 ms | Binary | |
| BinaryFormatter | 34751 | 961 ms | 488 ms | Binary | |
| ZeroFormatter | - | - | - | Binary | Not supported |
-Serialization against: ComplexContainer Collections
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 120 | 9 ms | 11 ms | Binary | |
| Salar.Bois.LZ4 | 114 | 27 ms | 12 ms | Binary | |
| Microsoft.Avro | - | - | - | Binary | Not supported |
| MessagePack | - | - | - | Binary | Not supported |
| protobuf-net | 171 | 14 ms | 24 ms | Binary | |
| BinaryFormatter | 7396 | 379 ms | 475 ms | Binary | |
| ZeroFormatter | - | - | - | Binary | Not supported |
-Serialization against: SpecializedCollections
| Serializer | Payload Size (bytes) | Serialization | Deserialization | Format | Note |
|---|---|---|---|---|---|
| Salar.Bois | 28 | 9 ms | 17 ms | Binary | |
| Salar.Bois.LZ4 | 29 | 22 ms | 17 ms | Binary | |
| Microsoft.Avro | - | - | - | Binary | Invalid Result |
| MessagePack | - | - | - | Binary | Not supported |
| MessagePackLZ4 | - | - | - | Binary | Not supported |
| protobuf-net | - | - | - | Binary | Not supported |
| BinaryFormatter | 2515 | 763 ms | 285 ms | Binary | |
| ZeroFormatter | - | - | - | Binary | Not supported |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Salar.BinaryBuffers (>= 3.4.0)
-
net6.0
- Salar.BinaryBuffers (>= 3.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0 | 43 | 7/15/2026 |
Adds the BOIS source-code-generation serializer package with generated reader and writer support.