MessagePack-CSharp
シリアライゼーションライブラリ
MessagePack-CSharp
概要
MessagePack-CSharpは、neueccによって開発されたC#/.NET向けの超高速MessagePackシリアライザーです。JSONの10倍以上の高速化を実現し、データサイズも大幅に削減できるバイナリシリアライゼーションライブラリです。.NET Standard 2.0準拠で、Unity、Xamarin、.NET Core、.NET Frameworkなど幅広いプラットフォームに対応しています。
詳細
MessagePack-CSharpは、パフォーマンスを最優先に設計されたシリアライザーで、ゼロアロケーション逆シリアル化、動的コード生成、バッファプーリングなどの最適化技術を採用しています。Source Generatorによるコンパイル時コード生成に対応し、AOT環境でも高速動作を実現します。
主な特徴:
- 超高速パフォーマンス: MsgPack-Cliの10倍、JSON.NETの17倍以上高速
- コンパクトなバイナリサイズ: JSONと比較して50-70%のサイズ削減
- Unity完全対応: Unity標準型(Vector3、Quaternionなど)の組み込みサポート
- Source Generator対応: AOT環境での動作とコンパイル時検証
- LZ4圧縮サポート: 高速圧縮による更なるサイズ削減
- Union型サポート: ポリモーフィックなシリアライゼーション
- セキュリティ機能: 信頼できないデータの安全な逆シリアル化
アーキテクチャ:
- インデックスキー(IntKey)による最速シリアライゼーション
- 文字列キー(StringKey)による可読性の高いデバッグ
- Contractlessモードによる属性不要のシリアライゼーション
- カスタムフォーマッターによる拡張性
メリット・デメリット
メリット
- 圧倒的なパフォーマンス: C#界隈で最速クラスのシリアライザー
- メモリ効率: ゼロアロケーション設計により GC圧力を最小化
- Unity統合: ゲーム開発での実績多数、Unity専用最適化
- 型安全性: Source Generatorによるコンパイル時検証
- 柔軟な設定: 用途に応じた3つのシリアライゼーションモード
- 圧縮対応: LZ4による高速圧縮でネットワーク転送最適化
- 活発な開発: Cysharpによる継続的なメンテナンス
デメリット
- バイナリフォーマット: 人間が読めない形式のため、デバッグが困難
- 学習曲線: 高度な機能を使いこなすには理解が必要
- 属性ベース: 基本的にはMessagePackObject属性の付与が必要
- バージョニング: スキーマ変更時の互換性管理に注意が必要
参考ページ
書き方の例
基本的なシリアライゼーション
// 1. インデックスキーを使用(最速)
[MessagePackObject]
public class Person
{
[Key(0)]
public int Id { get; set; }
[Key(1)]
public string Name { get; set; }
[Key(2)]
public int Age { get; set; }
[IgnoreMember]
public string IgnoredProperty { get; set; }
}
// シリアライゼーション
var person = new Person { Id = 1, Name = "田中", Age = 30 };
byte[] bytes = MessagePackSerializer.Serialize(person);
// 逆シリアライゼーション
Person deserialized = MessagePackSerializer.Deserialize<Person>(bytes);
// JSON形式で確認
string json = MessagePackSerializer.ConvertToJson(bytes);
Console.WriteLine(json); // [1,"田中",30]
文字列キーとContractlessモード
// 2. 文字列キー(デバッグしやすい)
[MessagePackObject]
public class Product
{
[Key("product_id")]
public int ProductId { get; set; }
[Key("name")]
public string Name { get; set; }
[Key("price")]
public decimal Price { get; set; }
}
// 3. Contractlessモード(属性不要)
public class Order
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public List<Product> Items { get; set; }
}
// Contractlessモードでのシリアライゼーション
var options = MessagePack.Resolvers.ContractlessStandardResolver.Options;
var order = new Order
{
OrderId = 1001,
OrderDate = DateTime.Now,
Items = new List<Product> { /* ... */ }
};
byte[] bytes = MessagePackSerializer.Serialize(order, options);
Order deserialized = MessagePackSerializer.Deserialize<Order>(bytes, options);
Unity向け最適化
// Unity初期化
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void InitializeMessagePack()
{
// Unity型のサポートを有効化
var options = MessagePackSerializerOptions.Standard
.WithResolver(MessagePack.Unity.UnityResolver.Instance);
MessagePackSerializer.DefaultOptions = options;
}
// Unity型のシリアライゼーション
[MessagePackObject]
public class GameData
{
[Key(0)]
public Vector3 Position { get; set; }
[Key(1)]
public Quaternion Rotation { get; set; }
[Key(2)]
public Color Color { get; set; }
}
// 高速な構造体配列のシリアライゼーション(Unsafe)
StaticCompositeResolver.Instance.Register(
MessagePack.Unity.UnityResolver.Instance,
MessagePack.Unity.Extension.UnityBlitWithPrimitiveArrayResolver.Instance,
MessagePack.Resolvers.StandardResolver.Instance
);
// メッシュデータなどの大量データに最適
Vector3[] vertices = mesh.vertices;
byte[] bytes = MessagePackSerializer.Serialize(vertices);
LZ4圧縮とセキュリティ設定
// LZ4圧縮を有効化
var lz4Options = MessagePackSerializerOptions.Standard
.WithCompression(MessagePackCompression.Lz4BlockArray);
byte[] compressed = MessagePackSerializer.Serialize(data, lz4Options);
var decompressed = MessagePackSerializer.Deserialize<MyData>(compressed, lz4Options);
// 信頼できないデータの処理
var secureOptions = MessagePackSerializerOptions.Standard
.WithSecurity(MessagePackSecurity.UntrustedData);
try
{
var result = MessagePackSerializer.Deserialize<MyData>(untrustedData, secureOptions);
}
catch (MessagePackSerializationException ex)
{
// セキュリティ違反を検出
Console.WriteLine($"セキュリティエラー: {ex.Message}");
}
Source GeneratorとAOT対応
// Source Generator用の属性
[GeneratedMessagePackResolver]
[MessagePackObject]
public partial class MyModel
{
[Key(0)]
public int Id { get; set; }
[Key(1)]
public string Name { get; set; }
}
// プロジェクトファイルでSource Generatorを有効化
// <PackageReference Include="MessagePack.Generator" Version="2.5.*" />
// 生成されたリゾルバーの使用
var options = MessagePackSerializerOptions.Standard
.WithResolver(GeneratedResolver.Instance);
// Unity IL2CPPなどAOT環境でも高速動作
MessagePackSerializer.DefaultOptions = options;
カスタムフォーマッター
// DateTimeを Unix時間で保存するカスタムフォーマッター
public class UnixTimeDateTimeFormatter : IMessagePackFormatter<DateTime>
{
public void Serialize(ref MessagePackWriter writer, DateTime value,
MessagePackSerializerOptions options)
{
var unixTime = ((DateTimeOffset)value).ToUnixTimeSeconds();
writer.Write(unixTime);
}
public DateTime Deserialize(ref MessagePackReader reader,
MessagePackSerializerOptions options)
{
var unixTime = reader.ReadInt64();
return DateTimeOffset.FromUnixTimeSeconds(unixTime).DateTime;
}
}
// カスタムフォーマッターの登録
var resolver = CompositeResolver.Create(
new IMessagePackFormatter[] { new UnixTimeDateTimeFormatter() },
new IFormatterResolver[] { StandardResolver.Instance }
);
var options = MessagePackSerializerOptions.Standard.WithResolver(resolver);
Union型(ポリモーフィズム)
[Union(0, typeof(Cat))]
[Union(1, typeof(Dog))]
public abstract class Animal
{
public abstract string MakeSound();
}
[MessagePackObject]
public class Cat : Animal
{
[Key(0)]
public string Name { get; set; }
public override string MakeSound() => "ニャー";
}
[MessagePackObject]
public class Dog : Animal
{
[Key(0)]
public string Name { get; set; }
[Key(1)]
public string Breed { get; set; }
public override string MakeSound() => "ワン";
}
// ポリモーフィックなシリアライゼーション
Animal[] animals = new Animal[]
{
new Cat { Name = "ミケ" },
new Dog { Name = "ポチ", Breed = "柴犬" }
};
byte[] bytes = MessagePackSerializer.Serialize(animals);
Animal[] deserialized = MessagePackSerializer.Deserialize<Animal[]>(bytes);