### Install MemoryPack Unity Package via Git URL Source: https://github.com/cysharp/memorypack/blob/main/README.md Install the MemoryPack.Unity package by referencing its Git URL. This method is used within Unity projects to integrate MemoryPack's Unity-specific extensions. ```git https://github.com/Cysharp/MemoryPack.git?path=src/MemoryPack.Unity/Assets/MemoryPack.Unity ``` -------------------------------- ### Unity Integration: Serialize and Deserialize PlayerState Source: https://context7.com/cysharp/memorypack/llms.txt Example of serializing and deserializing a `PlayerState` object in Unity using `MemoryPackSerializer`. ```csharp // Serialize var state = new PlayerState { Position = transform.position, Rotation = transform.rotation, Health = 100f }; byte[] bin = MemoryPackSerializer.Serialize(state); // Deserialize PlayerState? restored = MemoryPackSerializer.Deserialize(bin); transform.SetPositionAndRotation(restored!.Position, restored.Rotation); ``` -------------------------------- ### Install Specific Version of MemoryPack Unity Package Source: https://github.com/cysharp/memorypack/blob/main/README.md Install a specific version of the MemoryPack.Unity package by appending the version tag to the Git URL. This allows for precise version control in Unity projects. ```git https://github.com/Cysharp/MemoryPack.git?path=src/MemoryPack.Unity/Assets/MemoryPack.Unity#1.0.0 ``` -------------------------------- ### Union Type Serialization Example Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates how to serialize and deserialize data using interface types with union support. This example shows serialization of an interface type and then deserializing it back, using a switch statement to handle different concrete types. ```APIDOC ### Serialization callbacks ```csharp IUnionSample data = new FooClass() { XYZ = 999 }; // Serialize as interface type. var bin = MemoryPackSerializer.Serialize(data); // Deserialize as interface type. var reData = MemoryPackSerializer.Deserialize(bin); switch (reData) { case FooClass x: Console.WriteLine(x.XYZ); break; case BarClass x: Console.WriteLine(x.OPQ); break; default: break; } ``` ``` -------------------------------- ### Overwrite Deserialization Example Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates how to deserialize data into an existing object instance using the `ref` overload to reduce memory allocations. MemoryPack attempts to reuse the instance if certain conditions are met, otherwise, a new instance is created. ```csharp var person = new Person(); var bin = MemoryPackSerializer.Serialize(person); // overwrite data to existing instance. MemoryPackSerializer.Deserialize(bin, ref person); ``` -------------------------------- ### Usage Example: Serialize and Deserialize Person in TypeScript Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates how to create a Person object, serialize it to Uint8Array, send it via fetch, and deserialize it back from an ArrayBuffer. ```typescript let person = new Person(); person.id = crypto.randomUUID(); person.age = 30; person.firstName = "foo"; person.lastName = "bar"; person.dateOfBirth = new Date(1999, 12, 31, 0, 0, 0); person.gender = Gender.Other; person.emails = ["foo@bar.com", "zoo@bar.net"]; // serialize to Uint8Array let bin = Person.serialize(person); let blob = new Blob([bin.buffer], { type: "application/x-memorypack" }) let response = await fetch("http://localhost:5260/api", { method: "POST", body: blob, headers: { "Content-Type": "application/x-memorypack" } }); let buffer = await response.arrayBuffer(); // deserialize from ArrayBuffer let person2 = Person.deserialize(buffer); ``` -------------------------------- ### Apply String and Dictionary Formatters Source: https://github.com/cysharp/memorypack/blob/main/README.md Example of applying custom string and dictionary formatters to class members. Utf16StringFormatter is performant for UTF16 strings, and OrdinalIgnoreCaseStringDictionaryFormatter initializes dictionaries with a case-insensitive comparer. ```csharp [MemoryPackable] public partial class Sample { // serialize this member as UTF16 String, it is performant than UTF8 but in ASCII, size is larger(but non ASCII, sometimes smaller). [Utf16StringFormatter] public string? Text { get; set; } // In deserialize, Dictionary is initialized with StringComparer.OrdinalIgnoreCase. [OrdinalIgnoreCaseStringDictionaryFormatter] public Dictionary? Ids { get; set; } // In deserialize time, all string is interned(see: String.Intern). If similar values come repeatedly, it saves memory. [InternStringFormatter] public string? Flag { get; set; } } ``` -------------------------------- ### Usage of Generated TypeScript Code in Browser Source: https://context7.com/cysharp/memorypack/llms.txt Example of how to use the generated TypeScript code in a browser environment, including serialization, sending via fetch, and deserialization. ```typescript // Generated TypeScript usage (browser) import { OrderRequest } from "./OrderRequest.js"; const req = new OrderRequest(); req.orderId = crypto.randomUUID(); req.productName = "Widget"; req.quantity = 3; const bin: Uint8Array = OrderRequest.serialize(req); const blob = new Blob([bin.buffer], { type: "application/x-memorypack" }); const resp = await fetch("/api/order", { method: "POST", body: blob, headers: { "Content-Type": "application/x-memorypack" } }); const result = OrderRequest.deserialize(await resp.arrayBuffer()); ``` -------------------------------- ### Custom Formatter for AnimationCurve Source: https://github.com/cysharp/memorypack/blob/main/README.md Implement a custom MemoryPack formatter for external types like AnimationCurve. This example shows how to handle null values and serialize using a wrapper type. ```csharp public class AnimationCurveFormatter : MemoryPackFormatter { // Unity does not support scoped and TBufferWriter so change signature to `Serialize(ref MemoryPackWriter writer, ref AnimationCurve value)` public override void Serialize(ref MemoryPackWriter writer, scoped ref AnimationCurve? value) { if (value == null) { writer.WriteNullObjectHeader(); return; } writer.WritePackable(new SerializableAnimationCurve(value)); } public override void Deserialize(ref MemoryPackReader reader, scoped ref AnimationCurve? value) { if (reader.PeekIsNull()) { reader.Advance(1); // skip null block value = null; ``` -------------------------------- ### Version Tolerant Schema Evolution - Remove Member (NG) Source: https://github.com/cysharp/memorypack/blob/main/README.md Shows an example of removing a member from a `MemoryPackable` class, which is not supported for version tolerance. Removing members can lead to data loss or deserialization errors. ```csharp // Remove is NG. [MemoryPackable] public partial class VersionCheck { // public int Prop1 { get; set; } public long Prop2 { get; set; } } ``` -------------------------------- ### Configure Dual Target Frameworks Source: https://github.com/cysharp/memorypack/blob/main/README.md Configure dual target frameworks for .NET 7 projects to ensure compatibility with MemoryPack dependencies. This is crucial when a library has a dependency on MemoryPack and needs to support both older and newer .NET versions. ```xml netstandard2.1;net7.0 ``` -------------------------------- ### Multiple Constructors with [MemoryPackConstructor] Source: https://github.com/cysharp/memorypack/blob/main/README.md Illustrates how to use the [MemoryPackConstructor] attribute when a class has multiple constructors. The attribute explicitly designates the constructor to be used. ```csharp public partial class Person3 { public int Age { get; set; } public string Name { get; set; } public Person3() { } // If there are multiple constructors, then [MemoryPackConstructor] should be used [MemoryPackConstructor] public Person3(int age, string name) { this.Age = age; this.Name = name; } } ``` -------------------------------- ### Generated TypeScript Person Class Source: https://github.com/cysharp/memorypack/blob/main/README.md Example of a TypeScript class generated by MemoryPack, including static methods for serialization and deserialization. ```typescript import { MemoryPackWriter } from "./MemoryPackWriter.js"; import { MemoryPackReader } from "./MemoryPackReader.js"; import { Gender } from "./Gender.js"; export class Person { id: string; age: number; firstName: string | null; lastName: string | null; dateOfBirth: Date; gender: Gender; emails: (string | null)[] | null; constructor() { // snip... } static serialize(value: Person | null): Uint8Array { // snip... } static serializeCore(writer: MemoryPackWriter, value: Person | null): void { // snip... } static serializeArray(value: (Person | null)[] | null): Uint8Array { // snip... } static serializeArrayCore(writer: MemoryPackWriter, value: (Person | null)[] | null): void { // snip... } static deserialize(buffer: ArrayBuffer): Person | null { // snip... } static deserializeCore(reader: MemoryPackReader): Person | null { // snip... } static deserializeArray(buffer: ArrayBuffer): (Person | null)[] | null { // snip... } static deserializeArrayCore(reader: MemoryPackReader): (Person | null)[] | null { // snip... } } ``` -------------------------------- ### Parameterized Constructor with MemoryPackable Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates using a parameterized constructor with the [MemoryPackable] attribute. Parameter names must match member names case-insensitively. ```csharp [MemoryPackable] public partial class Person { public readonly int Age; public readonly string Name; // You can use a parameterized constructor - parameter names must match corresponding members name (case-insensitive) public Person(int age, string name) { this.Age = age; this.Name = name; } } ``` -------------------------------- ### Deserialize List with Object Reuse Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates deserializing a List where the list object is reused, avoiding new allocations during deserialization. CollectionsMarshal.AsSpan can be used to get a Span for efficient operations. ```csharp [MemoryPackable] public partial class ListBytesSample { public int Id { get; set; } public List Payload { get; set; } } // ---- // List is reused, no allocation in deserialize. MemoryPackSerializer.Deserialize(bin, ref reuseObject); // for efficient operation, you can get Span by CollectionsMarshal var span = CollectionsMarshal.AsSpan(value.Payload); ``` -------------------------------- ### Configure TypeScript Output Directory in .csproj Source: https://context7.com/cysharp/memorypack/llms.txt Configure the output directory and file extension for generated TypeScript files by setting properties in your .csproj file. ```xml $(MSBuildProjectDirectory)\wwwroot\js\memorypack .js true ``` -------------------------------- ### MemoryPack Serialize Overloads Source: https://github.com/cysharp/memorypack/blob/main/README.md Provides an overview of the `Serialize` method overloads. The `BufferWriter` overload is recommended for performance, especially when integrating with `System.IO.Pipelines` or ASP.NET Core's `BodyWriter`. ```csharp // Non generic API also available, these version is first argument is Type and value is object? byte[] Serialize(in T? value, MemoryPackSerializerOptions? options = default) void Serialize(in TBufferWriter bufferWriter, in T? value, MemoryPackSerializerOptions? options = default) async ValueTask SerializeAsync(Stream stream, T? value, MemoryPackSerializerOptions? options = default, CancellationToken cancellationToken = default) ``` -------------------------------- ### C# MemoryPack Instantiate from ServiceProvider Source: https://github.com/cysharp/memorypack/blob/main/README.md Use MemoryPackOnDeserializing with ref value to change the instance used for deserialization, enabling instantiation from a ServiceProvider. Ensure the ServiceProvider is configured in MemoryPackSerializerOptions. ```csharp // before using this formatter, set ServiceProvider // var options = MemoryPackSerializerOptions.Default with { ServiceProvider = provider }; // MemoryPackSerializer.Deserialize(value, options); [MemoryPackable] public partial class InstantiateFromServiceProvider { static IServiceProvider serviceProvider = default!; public int MyProperty { get; private set; } [MemoryPackOnDeserializing] static void OnDeserializing(ref MemoryPackReader reader, ref InstantiateFromServiceProvider value) { if (value != null) return; value = reader.Options.ServiceProvider!.GetRequiredService(); } } ``` -------------------------------- ### Rent OptionalState for MemoryPackWriter/Reader Source: https://github.com/cysharp/memorypack/blob/main/README.md Obtain and manage OptionalState for MemoryPackWriter and MemoryPackReader using MemoryPackWriterOptionalStatePool and MemoryPackReaderOptionalStatePool. The state is returned to the pool upon disposal. ```csharp // when disposed, OptionalState will return to pool. using(var state = MemoryPackWriterOptionalStatePool.Rent(MemoryPackSerializerOptions.Default)) { var writer = new MemoryPackWriter(ref t, state); } // for Reader using (var state = MemoryPackReaderOptionalStatePool.Rent(MemoryPackSerializerOptions.Default)) { var reader = new MemoryPackReader(buffer, state); } ``` -------------------------------- ### Version Tolerant Schema Evolution - Add Member Source: https://github.com/cysharp/memorypack/blob/main/README.md Illustrates adding a new member to a `MemoryPackable` class. This is a supported schema evolution for version tolerance, allowing new members to be added without breaking compatibility with older data. ```csharp [MemoryPackable] public partial class VersionCheck { public int Prop1 { get; set; } public long Prop2 { get; set; } } // Add is OK. [MemoryPackable] public partial class VersionCheck { public int Prop1 { get; set; } public long Prop2 { get; set; } public int? AddedProp { get; set; } } ``` -------------------------------- ### Create Dynamic Union Formatter Source: https://github.com/cysharp/memorypack/blob/main/README.md Assembles a union formatter dynamically using `DynamicUnionFormatter`. This is an alternative to attribute-based registration. Remember to manually register the formatter with `MemoryPackFormatterProvider.Register()`. ```csharp // (ushort, Type)[] var formatter = new DynamicUnionFormatter( (0, typeof(Foo)), (1, typeof(Bar)), (2, typeof(Baz)) ); MemoryPackFormatterProvider.Register(formatter); ``` -------------------------------- ### Version Tolerant Schema Evolution - Change Order (NG) Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates changing the order of members in a `MemoryPackable` class, which is not supported for version tolerance. Member order must be preserved to ensure correct deserialization. ```csharp // Change order is NG. [MemoryPackable] public partial class VersionCheck { public long Prop2 { get; set; } public int Prop1 { get; set; } } ``` -------------------------------- ### Configure TypeScript Output Directory in C# Source: https://github.com/cysharp/memorypack/blob/main/README.md Configure the MSBuild project to specify the output directory for generated TypeScript code. ```xml $(MSBuildProjectDirectory)\wwwroot\js\memorypack ``` -------------------------------- ### Unity Integration: Define PlayerState with MemoryPackable Source: https://context7.com/cysharp/memorypack/llms.txt Define a Unity `MonoBehaviour` class with `[MemoryPackable]` to enable serialization of Unity types like `Vector3` and `Quaternion`. ```csharp // Unity Package Manager → Add package from git URL: // https://github.com/Cysharp/MemoryPack.git?path=src/MemoryPack.Unity/Assets/MemoryPack.Unity#1.21.4 using MemoryPack; using UnityEngine; [MemoryPackable] public partial class PlayerState { public Vector3 Position { get; set; } public Quaternion Rotation { get; set; } public float Health { get; set; } } ``` -------------------------------- ### Configure Serialization Info Output Source: https://github.com/cysharp/memorypack/blob/main/README.md Configure the build process to output MemoryPack serialization information by setting the `MemoryPackGenerator_SerializationInfoOutputDirectory` MSBuild property. This helps in detecting schema changes. ```xml $(MSBuildProjectDirectory)\MemoryPackLogs ``` -------------------------------- ### Brotli Compression and Decompression Source: https://context7.com/cysharp/memorypack/llms.txt Use BrotliCompressor and BrotliDecompressor for efficient whole-object compression. Ensure to dispose of these objects after use. ```csharp using MemoryPack; using MemoryPack.Compression; [MemoryPackable] public partial class LargePayload { public byte[]? Data { get; set; } } var value = new LargePayload { Data = new byte[100_000] }; // --- Compress --- using var compressor = new BrotliCompressor(); // quality=1 (Fastest), window=22 MemoryPackSerializer.Serialize(compressor, value); byte[] compressed = compressor.ToArray(); // or copy directly to an ASP.NET Core PipeWriter: // compressor.CopyTo(response.BodyWriter); // --- Decompress --- using var decompressor = new BrotliDecompressor(); ReadOnlySequence decompressedSeq = decompressor.Decompress(compressed); LargePayload? restored = MemoryPackSerializer.Deserialize(decompressedSeq); ``` -------------------------------- ### Record Primary Constructor with MemoryPackable Source: https://github.com/cysharp/memorypack/blob/main/README.md Shows support for record primary constructors when using the [MemoryPackable] attribute. ```csharp // also supports record primary constructor [MemoryPackable] public partial record Person2(int Age, string Name); ``` -------------------------------- ### Serialize and Deserialize Objects with MemoryPack Source: https://github.com/cysharp/memorypack/blob/main/README.md Use `MemoryPackSerializer.Serialize` and `MemoryPackSerializer.Deserialize` to convert objects to and from byte arrays. The `Serialize` method supports `IBufferWriter` and `Stream`, while `Deserialize` supports `ReadOnlySpan`, `ReadOnlySequence`, and `Stream`. ```csharp var v = new Person { Age = 40, Name = "John" }; var bin = MemoryPackSerializer.Serialize(v); var val = MemoryPackSerializer.Deserialize(bin); ``` -------------------------------- ### Apply BrotliStringFormatter for Strings Source: https://github.com/cysharp/memorypack/blob/main/README.md Compresses strings (UTF16) using the Brotli algorithm. Use BrotliFormatter or BrotliStringFormatter for byte[] or string respectively for optimal performance. ```csharp [MemoryPackable] public partial class Sample { public int Id { get; set; } [BrotliStringFormatter] public string? LargeText { get; set; } } ``` -------------------------------- ### MemoryPackSerializerOptions with Pooling Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates how to use MemoryPackSerializerOptions to manage memory pooling during deserialization. The OnDeserialized callback is used to enable pooling, and the Dispose method returns the payload to the ArrayPool. ```csharp bool usePool; [MemoryPackOnDeserialized] void OnDeserialized() { usePool = true; } public void Dispose() { if (!usePool) return; Return(Payload); Payload = default; } static void Return(Memory memory) => Return((ReadOnlyMemory)memory); static void Return(ReadOnlyMemory memory) { if (MemoryMarshal.TryGetArray(memory, out var segment) && segment.Array is { Length: > 0 }) { ArrayPool.Shared.Return(segment.Array, clearArray: RuntimeHelpers.IsReferenceOrContainsReferences()); } } ``` ```csharp using(var value = MemoryPackSerializer.Deserialize(bin)) { // do anything... } // return to ArrayPool ``` -------------------------------- ### Version Tolerant Schema Evolution with MemoryPack Source: https://context7.com/cysharp/memorypack/llms.txt Use GenerateType.VersionTolerant for safe addition and deletion of members. Ensure all members use [MemoryPackOrder] explicitly, and never reuse orders of deleted members. ```csharp using MemoryPack; [MemoryPackable(GenerateType.VersionTolerant)] public partial class ApiResponse { [MemoryPackOrder(0)] public int StatusCode { get; set; } [MemoryPackOrder(1)] public string? Message { get; set; } // Added in v2 — old readers safely skip this field [MemoryPackOrder(2)] public DateTime? Timestamp { get; set; } } // Serialized with v2 schema, deserialized by v1 reader: StatusCode and Message are populated, Timestamp silently ignored // Serialized with v1 schema, deserialized by v2 reader: Timestamp is default(null) byte[] v2Bin = MemoryPackSerializer.Serialize(new ApiResponse { StatusCode = 200, Message = "OK", Timestamp = DateTime.UtcNow }); ``` -------------------------------- ### MemoryPackSerializerOptions for Encoding and ServiceProvider Source: https://context7.com/cysharp/memorypack/llms.txt Configure string encoding (Utf8/Utf16) and provide an IServiceProvider for DI access within serialization callbacks using MemoryPackSerializerOptions. Use the 'with' expression for easy modification. ```csharp using MemoryPack; // UTF-16 encoding — faster for ASCII-heavy strings, larger payload byte[] utf16 = MemoryPackSerializer.Serialize(value, MemoryPackSerializerOptions.Utf16); // Provide DI services accessible during deserialization var options = MemoryPackSerializerOptions.Default with { ServiceProvider = serviceProvider }; [MemoryPackable] public partial class ServiceAware { public int Value { get; set; } [MemoryPackOnDeserializing] static void Init(ref MemoryPackReader reader, ref ServiceAware? value) { if (value == null) value = reader.Options.ServiceProvider!.GetRequiredService(); } } ``` -------------------------------- ### Unity Integration: Manual Union Formatter Registration Source: https://context7.com/cysharp/memorypack/llms.txt Manually register union formatters in Unity by calling an initializer method, as `ModuleInitializer` is not supported. ```csharp // Manual union formatter registration (required in Unity, replaces ModuleInitializer) // In your startup MonoBehaviour: MyUnionFormatterInitializer.RegisterFormatter(); ``` -------------------------------- ### Define Serializable Class with MemoryPackable Source: https://github.com/cysharp/memorypack/blob/main/README.md Annotate your class with `[MemoryPackable]` and the `partial` keyword to enable MemoryPack's source generator for serialization. ```csharp using MemoryPack; [MemoryPackable] public partial class Person { public int Age { get; set; } public string Name { get; set; } } ``` -------------------------------- ### Serialize Source: https://github.com/cysharp/memorypack/blob/main/README.md Provides three overloads for serializing data. The generic `Serialize` is for direct byte array output. The `Serialize` overload is recommended for performance as it serializes directly into a buffer, suitable for `PipeWriter` or `BodyWriter`. The `SerializeAsync` overload is for asynchronous serialization to a stream. ```APIDOC ## Serialize API `Serialize` has three overloads. ```csharp // Non generic API also available, these version is first argument is Type and value is object? byte[] Serialize(in T? value, MemoryPackSerializerOptions? options = default) void Serialize(in TBufferWriter bufferWriter, in T? value, MemoryPackSerializerOptions? options = default) async ValueTask SerializeAsync(Stream stream, T? value, MemoryPackSerializerOptions? options = default, CancellationToken cancellationToken = default) ``` For performance, the recommended API uses `BufferWriter`. This serializes directly into the buffer. It can be applied to `PipeWriter` in `System.IO.Pipelines`, `BodyWriter` in ASP .NET Core, etc. If a `byte[]` is required (e.g. `RedisValue` in [StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis)), the return `byte[]` API is simple and almost as fast. Note that `SerializeAsync` for `Stream` is asynchronous only for Flush; it serializes everything once into MemoryPack's internal pool buffer and then writes using `WriteAsync`. Therefore, the `BufferWriter` overload, which separates and controls buffer and flush, is better. If you want to do a complete streaming write, see the [Streaming Serialization](#streaming-serialization) section. ``` -------------------------------- ### Define Serializable Types with [MemoryPackable] Source: https://context7.com/cysharp/memorypack/llms.txt Annotate classes, structs, records, and record structs with [MemoryPackable] and partial. Use [MemoryPackIgnore] to exclude members and [MemoryPackInclude] to promote private members. ```csharp using MemoryPack; [MemoryPackable] public partial class SampleClass { public int PublicField; public string? PublicProperty { get; set; } [MemoryPackIgnore] // excluded from serialization public int Computed => PublicField * 2; [MemoryPackInclude] // private member promoted to serialized private string? _secret; } // record primary constructor - fully supported [MemoryPackable] public partial record Point(float X, float Y); // Explicit constructor selection when multiple constructors exist [MemoryPackable] public partial class Order { public int Id { get; } public string? Item { get; } public Order() { } [MemoryPackConstructor] public Order(int id, string? item) { Id = id; Item = item; } } // Custom member order [MemoryPackable(SerializeLayout.Explicit)] public partial class Explicit { [MemoryPackOrder(1)] public int B { get; set; } [MemoryPackOrder(0)] public int A { get; set; } } ``` -------------------------------- ### Brotli Compression with MemoryPack Source: https://github.com/cysharp/memorypack/blob/main/README.md Use BrotliCompressor for efficient compression of serialized data. Ensure to use 'using' to release memory pools. The default compression level is Fastest (quality-1). ```csharp using MemoryPack.Compression; // Compression(require using) using var compressor = new BrotliCompressor(); MemoryPackSerializer.Serialize(compressor, value); // Get compressed byte[] var compressedBytes = compressor.ToArray(); // Or write to other IBufferWriter(for example PipeWriter) compressor.CopyTo(response.BodyWriter); ``` -------------------------------- ### C# MemoryPack Callbacks with Ref Parameters Source: https://github.com/cysharp/memorypack/blob/main/README.md Callbacks can accept ref parameters for MemoryPackWriter and MemoryPackReader, allowing custom header writing/reading before serialization/deserialization. Ensure correct .NET Standard compatibility for IBufferWriter. ```csharp [MemoryPackable] public partial class EmitIdData { public int MyProperty { get; set; } [MemoryPackOnSerializing] static void WriteId(ref MemoryPackWriter writer, ref EmitIdData? value) where TBufferWriter : IBufferWriter // .NET Standard 2.1, use where TBufferWriter : class, IBufferWriter { writer.WriteUnmanaged(Guid.NewGuid()); // emit GUID in header. } [MemoryPackOnDeserializing] static void ReadId(ref MemoryPackReader reader, ref EmitIdData? value) { // read custom header before deserialize var guid = reader.ReadUnmanaged(); Console.WriteLine(guid); } } ``` -------------------------------- ### Serialize and Deserialize Interface Type Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates serializing and deserializing an object using its interface type. Ensure all possible derived types are handled in the switch statement. ```csharp IUnionSample data = new FooClass() { XYZ = 999 }; // Serialize as interface type. var bin = MemoryPackSerializer.Serialize(data); // Deserialize as interface type. var reData = MemoryPackSerializer.Deserialize(bin); switch (reData) { case FooClass x: Console.WriteLine(x.XYZ); break; case BarClass x: Console.WriteLine(x.OPQ); break; default: break; } ``` -------------------------------- ### Serialization Callbacks in MemoryPack Source: https://context7.com/cysharp/memorypack/llms.txt Use attributes like [MemoryPackOnSerializing] and [MemoryPackOnDeserialized] to hook into the serialization/deserialization lifecycle. Static methods with specific signatures can read/write custom headers. ```csharp using MemoryPack; [MemoryPackable] public partial class AuditLog { public Guid Id { get; set; } public string? Message { get; set; } [MemoryPackOnSerializing] void OnSerializing() => Console.WriteLine($"Serializing {Id}"); [MemoryPackOnDeserialized] void OnDeserialized() => Console.WriteLine($"Deserialized {Id}"); // Write a custom GUID header before the object fields [MemoryPackOnSerializing] static void WriteHeader(ref MemoryPackWriter writer, ref AuditLog? value) where TBufferWriter : IBufferWriter { writer.WriteUnmanaged(Guid.NewGuid()); // custom header } [MemoryPackOnDeserializing] static void ReadHeader(ref MemoryPackReader reader, ref AuditLog? value) { var headerGuid = reader.ReadUnmanaged(); Console.WriteLine($"Header GUID: {headerGuid}"); } } ``` -------------------------------- ### Explicit Member Ordering for Serialization Source: https://github.com/cysharp/memorypack/blob/main/README.md Control the serialization order of members using [MemoryPackable(SerializeLayout.Explicit)] and [MemoryPackOrder()]. This is crucial for schema evolution as the order cannot change during deserialization. ```csharp // serialize Prop0 -> Prop1 [MemoryPackable(SerializeLayout.Explicit)] public partial class SampleExplicitOrder { [MemoryPackOrder(1)] public int Prop1 { get; set; } [MemoryPackOrder(0)] public int Prop0 { get; set; } } ``` -------------------------------- ### Implement Custom MemoryPack Formatter Source: https://github.com/cysharp/memorypack/blob/main/README.md Inherit MemoryPackFormatter and override Serialize and Deserialize methods to implement custom serialization logic for a specific type. Ensure the formatter is registered with MemoryPackFormatterProvider. ```csharp public class SkeltonFormatter : MemoryPackFormatter { public override void Serialize(ref MemoryPackWriter writer, scoped ref Skelton? value) { if (value == null) { writer.WriteNullObjectHeader(); return; } // use writer method. } public override void Deserialize(ref MemoryPackReader reader, scoped ref Skelton? value) { if (!reader.TryReadObjectHeader(out var count)) { value = null; return; } // use reader method. } } ``` ```csharp MemoryPackFormatterProvider.Register(new SkeltonFormatter()); ``` -------------------------------- ### Custom Collection Serialization with MemoryPack Source: https://context7.com/cysharp/memorypack/llms.txt Utilize GenerateType.Collection for types implementing ICollection, ISet, or IDictionary to serialize them as collections instead of plain objects. ```csharp using MemoryPack; [MemoryPackable(GenerateType.Collection)] public partial class TagList : List { } [MemoryPackable(GenerateType.Collection)] public partial class StringIndex : Dictionary { } var tags = new TagList { "alpha", "beta", "gamma" }; byte[] bin = MemoryPackSerializer.Serialize(tags); TagList? result = MemoryPackSerializer.Deserialize(bin); // result contains ["alpha", "beta", "gamma"] ``` -------------------------------- ### Version-Tolerant Serialization with Sequential Layout Source: https://github.com/cysharp/memorypack/blob/main/README.md When `SerializeLayout.Sequential` is explicitly set with `GenerateType.VersionTolerant`, automatic ordering is allowed. However, this configuration does not permit member removal for version tolerance. ```csharp [MemoryPackable(GenerateType.VersionTolerant, SerializeLayout.Sequential)] public partial class VersionTolerantObject3 { public int MyProperty0 { get; set; } = default; public long MyProperty1 { get; set; } = default; public short MyProperty2 { get; set; } = default; } ``` -------------------------------- ### Suppress Default Initialization with [SuppressDefaultInitialization] Source: https://context7.com/cysharp/memorypack/llms.txt Apply [SuppressDefaultInitialization] to fields to prevent them from resetting to their default values when deserializing older binary formats that lack these fields. This is useful for adding new fields with meaningful defaults. ```csharp using MemoryPack; [MemoryPackable] public partial class Config { public string? Name { get; set; } [SuppressDefaultInitialization] public int MaxRetries { get; set; } = 3; // stays 3 if absent in old binary public int Timeout { get; set; } = 30; // resets to default(0) if absent in old binary } ``` -------------------------------- ### Runtime Union Registration with DynamicUnionFormatter Source: https://context7.com/cysharp/memorypack/llms.txt Register unions at runtime using DynamicUnionFormatter when the full set of subtypes is unknown at compile time. Register via MemoryPackFormatterProvider.Register. ```csharp using MemoryPack; using MemoryPack.Formatters; public interface IEvent { } [MemoryPackable] public partial class ClickEvent : IEvent { public int X { get; set; } public int Y { get; set; } } [MemoryPackable] public partial class KeyEvent : IEvent { public string? Key { get; set; } } // Register at application startup var formatter = new DynamicUnionFormatter( (0, typeof(ClickEvent)), (1, typeof(KeyEvent)) ); MemoryPackFormatterProvider.Register(formatter); IEvent evt = new ClickEvent { X = 100, Y = 200 }; byte[] bin = MemoryPackSerializer.Serialize(evt); IEvent? restored = MemoryPackSerializer.Deserialize(bin); // restored is ClickEvent { X=100, Y=200 } ``` -------------------------------- ### Overwrite Deserialization Source: https://github.com/cysharp/memorypack/blob/main/README.md Demonstrates how to deserialize data into an existing object instance to reduce memory allocations. This is achieved using the `ref T? value` overloads of the Deserialize methods. ```APIDOC ## Overwrite Deserialization Example ### Description MemoryPack supports deserializing data into an existing instance to minimize allocations. This is particularly useful for performance-sensitive applications. ### Method - `int Deserialize(ReadOnlySpan buffer, ref T? value)` - `int Deserialize(in ReadOnlySequence buffer, ref T? value)` ### Parameters - `buffer` (ReadOnlySpan or ReadOnlySequence): The buffer containing the serialized data. - `value` (ref T?): A reference to the existing object instance to be overwritten. ### Request Example ```csharp var person = new Person(); var bin = MemoryPackSerializer.Serialize(person); // Overwrite data into the existing 'person' instance. MemoryPackSerializer.Deserialize(bin, ref person); ``` ### Response #### Success Response (200) - `int`: The number of bytes read from the buffer. ### Notes MemoryPack attempts to overwrite the existing instance. However, if certain conditions are not met (e.g., null reference, parameterized constructor, mismatched array length, incompatible collection types), a new instance will be created. ``` -------------------------------- ### Annotating Classes with MemoryPackable Source: https://github.com/cysharp/memorypack/blob/main/README.md Use the [MemoryPackable] attribute on classes, structs, records, and record structs to enable automatic serialization. By default, public instance properties and fields are serialized. Use [MemoryPackIgnore] to exclude members and [MemoryPackInclude] to serialize private members. ```csharp [MemoryPackable] public partial class Sample { // these types are serialized by default public int PublicField; public readonly int PublicReadOnlyField; public int PublicProperty { get; set; } public int PrivateSetPublicProperty { get; private set; } public int ReadOnlyPublicProperty { get; } public int InitProperty { get; init; } public required int RequiredInitProperty { get; init; } // these types are not serialized by default int privateProperty { get; set; } int privateField; readonly int privateReadOnlyField; // use [MemoryPackIgnore] to remove target of a public member [MemoryPackIgnore] public int PublicProperty2 => PublicProperty + PublicField; // use [MemoryPackInclude] to promote a private member to serialization target [MemoryPackInclude] int privateField2; [MemoryPackInclude] int privateProperty2 { get; set; } } ``` -------------------------------- ### Define Custom MemoryPack Formatter Attribute Source: https://github.com/cysharp/memorypack/blob/main/README.md Abstract base class for creating custom formatters for specific types. Implement GetFormatter to provide the IMemoryPackFormatter instance. ```csharp [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] public abstract class MemoryPackCustomFormatterAttribute : Attribute { public abstract IMemoryPackFormatter GetFormatter(); } ``` -------------------------------- ### Deserialize Data with MemoryPack Source: https://context7.com/cysharp/memorypack/llms.txt Deserializes data from ReadOnlySpan, ReadOnlySequence, or Stream. Includes ref overloads for in-place deserialization to minimize allocations. ```csharp using MemoryPack; // Deserialize from byte[] / ReadOnlySpan byte[] bin = MemoryPackSerializer.Serialize(new Person { Age = 25, Name = "Bob" }); Person? person = MemoryPackSerializer.Deserialize(bin); Console.WriteLine(person?.Name); // Bob // Overwrite existing instance (reduces allocations) var reuse = new Person(); MemoryPackSerializer.Deserialize(bin, ref reuse); Console.WriteLine(reuse.Name); // Bob // Deserialize from ReadOnlySequence ReadOnlySequence seq = new ReadOnlySequence(bin); Person? p2 = MemoryPackSerializer.Deserialize(seq); // Async from Stream using var stream = new MemoryStream(bin); Person? p3 = await MemoryPackSerializer.DeserializeAsync(stream); // Non-generic overload object? obj = MemoryPackSerializer.Deserialize(typeof(Person), bin); ``` -------------------------------- ### Serialize Data with MemoryPack Source: https://context7.com/cysharp/memorypack/llms.txt Serializes a value to byte array, IBufferWriter, or Stream. Supports options for string encoding (UTF-8/UTF-16) and non-generic overloads. ```csharp using MemoryPack; [MemoryPackable] public partial class Person { public int Age { get; set; } public string? Name { get; set; } } // Serialize to byte[] var person = new Person { Age = 30, Name = "Alice" }; byte[] bin = MemoryPackSerializer.Serialize(person); // bin contains the raw MemoryPack binary payload // Serialize to IBufferWriter (e.g. ArrayBufferWriter, PipeWriter) var bufferWriter = new System.Buffers.ArrayBufferWriter(); MemoryPackSerializer.Serialize(bufferWriter, person); // Serialize to Stream (async) using var stream = new MemoryStream(); await MemoryPackSerializer.SerializeAsync(stream, person); // UTF-16 string encoding option byte[] utf16Bin = MemoryPackSerializer.Serialize(person, MemoryPackSerializerOptions.Utf16); // Non-generic (type-erased) overload byte[] bin2 = MemoryPackSerializer.Serialize(typeof(Person), person); ``` -------------------------------- ### C# MemoryPack Static Constructor Alternative Source: https://github.com/cysharp/memorypack/blob/main/README.md MemoryPackable classes cannot define static constructors directly. Use a static partial void StaticConstructor() method instead, which the generated partial class will utilize. ```csharp [MemoryPackable] public partial class CctorSample { static partial void StaticConstructor() { } } ``` -------------------------------- ### Configure TypeScript Generation Properties Source: https://github.com/cysharp/memorypack/blob/main/README.md Use these MSBuild properties to customize TypeScript output, such as the import file extension, member name casing, output directory, and nullable type generation. ```xml $(MSBuildProjectDirectory)\wwwroot\js\memorypack false true ``` -------------------------------- ### Wrapper Type for External Serialization Source: https://github.com/cysharp/memorypack/blob/main/README.md Create a wrapper struct to serialize external types like Unity's AnimationCurve. Use [MemoryPackIgnore] for the original type and [MemoryPackInclude] for serializable properties. Ensure appropriate constructors are present. ```csharp // Keyframe: (float time, float inTangent, float outTangent, int tangentMode, int weightedMode, float inWeight, float outWeight) [MemoryPackable] public readonly partial struct SerializableAnimationCurve { [MemoryPackIgnore] public readonly AnimationCurve AnimationCurve; [MemoryPackInclude] WrapMode preWrapMode => AnimationCurve.preWrapMode; [MemoryPackInclude] WrapMode postWrapMode => AnimationCurve.postWrapMode; [MemoryPackInclude] Keyframe[] keys => AnimationCurve.keys; [MemoryPackConstructor] SerializableAnimationCurve(WrapMode preWrapMode, WrapMode postWrapMode, Keyframe[] keys) { var curve = new AnimationCurve(keys); curve.preWrapMode = preWrapMode; curve.postWrapMode = postWrapMode; this.AnimationCurve = curve; } public SerializableAnimationCurve(AnimationCurve animationCurve) { this.AnimationCurve = animationCurve; } } ``` -------------------------------- ### Circular Reference Support with MemoryPack Source: https://github.com/cysharp/memorypack/blob/main/README.md Enable circular reference support by using `GenerateType.CircularReference`. This allows for the serialization of object graphs with cyclic dependencies, similar to `System.Text.Json`'s preserve-references. ```csharp // to enable circular-reference, use GenerateType.CircularReference [MemoryPackable(GenerateType.CircularReference)] public partial class Node { [MemoryPackOrder(0)] public Node? Parent { get; set; } [MemoryPackOrder(1)] public Node[]? Children { get; set; } } ``` ```csharp // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/preserve-references?pivots=dotnet-7-0 Employee tyler = new() { Name = "Tyler Stein" }; Employee adrian = new() { Name = "Adrian King" }; tyler.DirectReports = new List { adrian }; adrian.Manager = tyler; var bin = MemoryPackSerializer.Serialize(tyler); Employee? tylerDeserialized = MemoryPackSerializer.Deserialize(bin); Console.WriteLine(tylerDeserialized?.DirectReports?[0].Manager == tylerDeserialized); // true [MemoryPackable(GenerateType.CircularReference)] public partial class Employee { [MemoryPackOrder(0)] public string? Name { get; set; } [MemoryPackOrder(1)] public Employee? Manager { get; set; } [MemoryPackOrder(2)] public List? DirectReports { get; set; } } ``` -------------------------------- ### Brotli Decompression with MemoryPack Source: https://github.com/cysharp/memorypack/blob/main/README.md Utilize BrotliDecompressor to decompress data serialized with BrotliCompressor. Remember to use 'using' for proper memory management. This can handle various input buffer types. ```csharp using MemoryPack.Compression; // Decompression(require using) using var decompressor = new BrotliDecompressor(); // Get decompressed ReadOnlySequence from ReadOnlySpan or ReadOnlySequence var decompressedBuffer = decompressor.Decompress(buffer); var value = MemoryPackSerializer.Deserialize(decompressedBuffer); ``` -------------------------------- ### Core Serialization: MemoryPackSerializer.Serialize Source: https://context7.com/cysharp/memorypack/llms.txt Serializes a value to byte array, IBufferWriter, or Stream. Supports optional options for string encoding and DI. ```APIDOC ## Serialize to byte[] ```csharp var person = new Person { Age = 30, Name = "Alice" }; byte[] bin = MemoryPackSerializer.Serialize(person); ``` ## Serialize to IBufferWriter ```csharp var bufferWriter = new System.Buffers.ArrayBufferWriter(); MemoryPackSerializer.Serialize(bufferWriter, person); ``` ## Serialize to Stream (async) ```csharp using var stream = new MemoryStream(); await MemoryPackSerializer.SerializeAsync(stream, person); ``` ## UTF-16 string encoding option ```csharp byte[] utf16Bin = MemoryPackSerializer.Serialize(person, MemoryPackSerializerOptions.Utf16); ``` ## Non-generic (type-erased) overload ```csharp byte[] bin2 = MemoryPackSerializer.Serialize(typeof(Person), person); ``` ``` -------------------------------- ### Registering Custom Formatters with MemoryPackFormatterProvider Source: https://context7.com/cysharp/memorypack/llms.txt Globally register custom MemoryPackFormatters for specific types or collection types using MemoryPackFormatterProvider. Use Register for concrete types and RegisterCollection/RegisterGenericType for more complex scenarios. ```csharp using MemoryPack; // Custom formatter for an external type public class DateOnlyFormatter : MemoryPackFormatter { public override void Serialize(ref MemoryPackWriter writer, scoped ref DateOnly value) => writer.WriteUnmanaged(value.DayNumber); public override void Deserialize(ref MemoryPackReader reader, scoped ref DateOnly value) { reader.ReadUnmanaged(out int dayNumber); value = DateOnly.FromDayNumber(dayNumber); } } // At application startup MemoryPackFormatterProvider.Register(new DateOnlyFormatter()); // Register a custom generic collection MemoryPackFormatterProvider.RegisterCollection, string>(); ``` -------------------------------- ### Streaming Collection Serialization with MemoryPackStreamingSerializer Source: https://context7.com/cysharp/memorypack/llms.txt Serialize large IEnumerable collections in chunks to a PipeWriter or Stream using MemoryPackStreamingSerializer. Deserialize back as IAsyncEnumerable. FlushRate controls chunk size. ```csharp using MemoryPack; using MemoryPack.Streaming; using System.IO.Pipelines; [MemoryPackable] public partial class LogEntry { public DateTime At { get; set; } public string? Text { get; set; } } // --- Serialize 1 million records to a stream in chunks --- IEnumerable GetLogs() => Enumerable.Range(0, 1_000_000) .Select(i => new LogEntry { At = DateTime.UtcNow, Text = $"event-{i}"}); using var pipe = new Pipe(); await MemoryPackStreamingSerializer.SerializeAsync( pipe.Writer, count: 1_000_000, source: GetLogs(), flushRate: 65536); // flush every 64 KB // --- Deserialize as async stream --- await foreach (var entry in MemoryPackStreamingSerializer.DeserializeAsync(pipe.Reader)) { Console.WriteLine(entry?.Text); } ```