高度な API (MessagePackSerializer)
MessagePackSerializer クラスは、C# 用の MessagePack のエントリ ポイントです。静的メソッドは、MessagePack for C# のメイン API を構成します。
API | 説明 |
---|---|
Serialize<T> |
オブジェクト グラフを MessagePack バイナリ ブロックにシリアル化します。ストリームは、async バリアントを使用して取得できます。非ジェネリックなオーバーロードも使用できます。 |
Deserialize<T> |
MessagePack バイナリをオブジェクト グラフに変換します。ストリームで使用できる非同期バリアント。非ジェネリックなオーバーロードも使用できます。 |
SerializeToJson |
MessagePack 互換のオブジェクト グラフを MessagePack の代わりに JSON にシリアル化します。これはデバッグに役立ちます。 |
ConvertToJson |
MessagePack バイナリを JSON に変換します。これはデバッグに役立ちます |
ConvertFromJson |
JSON を MessagePack バイナリに変換します。 |
MessagePack for C# は基本的にシリアル化に IBufferWriter <byte> を使用し、逆シリアル化に ReadOnlySequence <byte> または Memory <byte> を使用します。コンビニエンス メソッド オーバーロードは、一般的なバッファ型と .NET Stream クラスを簡単に操作できるように提供されていますが、これらのコンビニエンス オーバーロードではバッファを 1 回コピーする必要があるため、ある程度のオーバーヘッドが発生します。
高レベル API は内部でメモリ プールを使用して、不必要なメモリ割り当てを回避します。結果のサイズが 64K 未満の場合、GC メモリは返されたバイトに対してのみ割り当てられます。
各シリアル化/逆シリアル化メソッドは、オプションで MessagePackSerializerOptions パラメーターを受け入れます。これを使用して、LZ4 圧縮サポートを使用またはアクティブ化するカスタム IFormatterResolver を指定できます。
単一のストリーム上の複数の MessagePack 構造
複数の連続する MessagePack データ構造を含むストリームを逆シリアル化するには、MessagePackStreamReader クラスを使用して、各データ構造の ReadOnlySequence<byte> を効率的に識別し、それを逆シリアル化できます。例えば:
static async Task<List<T>> DeserializeListFromStreamAsync<T>(Stream stream, CancellationToken cancellationToken)
{
var dataStructures = new List<T>();
using (var streamReader = new MessagePackStreamReader(stream))
{
while (await streamReader.ReadAsync(cancellationToken) is ReadOnlySequence<byte> msgpack)
{
dataStructures.Add(MessagePackSerializer.Deserialize<T>(msgpack, cancellationToken: cancellationToken));
}
}
return dataStructures;
}
低レベル API (IMessagePackFormatter<T>)
IMessagePackFormatter<T> インターフェイスは、一意の型をシリアル化する役割を果たします。たとえば、Int32Formatter: IMessagePackFormatter<Int32> は Int32 MessagePack シリアライザーを表します。
public interface IMessagePackFormatter<T>
{
void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options);
T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options);
}
MessagePack.Formatters の下には、多くの組み込みフォーマッタがあります。通常、カスタム型は、動的コード生成を使用して新しい IMessagePackFormatter<T> 型の組み込み型パーサーを生成することにより、自動的にサポートされます。この機能をサポートしていないプラットフォームについては、AOT コード生成のサポートを参照してください。
ただし、一部の型 (特にサードパーティのライブラリやランタイム自体によって提供される型) には適切に注釈を付けることができず、コントラクトなしのシリアル化では非効率な結果が生成されたり、さらには誤った結果が生成される可能性があります。このようなカスタム型のシリアル化をより詳細に制御するには、独自の IMessagePackFormatter<T> 実装を作成します。以下は、そのようなカスタム フォーマッタ実装の例です。次のセクションで説明するオリジナルの API を使用することに注意してください。
/// <summary>Serializes a <see cref="FileInfo" /> by its full path as a string.</summary>
public class FileInfoFormatter : IMessagePackFormatter<FileInfo>
{
public void Serialize(
ref MessagePackWriter writer, FileInfo value, MessagePackSerializerOptions options)
{
if (value == null)
{
writer.WriteNil();
return;
}
writer.WriteString(value.FullName);
}
public FileInfo Deserialize(
ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
return null;
}
options.Security.DepthStep(ref reader);
var path = reader.ReadString();
reader.Depth--;
return new FileInfo(path);
}
}
DepthStep ステートメントと Depth-- ステートメントは、信頼できないデータを逆シリアル化し、スタック オーバーフロー例外を引き起こしてプロセスをクラッシュさせるパケット データを送信するときに、サービス拒否攻撃につながる可能性のあるセキュリティ層を提供します。これら 2 つのステートメントは、IMessagePackFormatter<T>.Deserialize メソッドの主要部分を囲む必要があります。
注: メッセージ パック フォーマッタはデータ構造の読み取りと書き込みを行う必要があります。上の例では、文字列の読み取りまたは書き込みを行っているだけです。記述する要素が複数ある場合は、先頭にマップまたは配列ヘッダーを追加する必要があります。逆シリアル化中にマップ/配列全体を読み取る必要があります。例えば:
public class MySpecialObjectFormatter : IMessagePackFormatter<MySpecialObject>
{
public void Serialize(
ref MessagePackWriter writer, MySpecialObject value, MessagePackSerializerOptions options)
{
if (value == null)
{
writer.WriteNil();
return;
}
writer.WriteArrayHeader(2);
writer.WriteString(value.FullName);
writer.WriteString(value.Age);
}
public MySpecialObject Deserialize(
ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
return null;
}
options.Security.DepthStep(ref reader);
string fullName = null;
int age = 0;
// Loop over *all* array elements independently of how many we expect,
// since if we're serializing an older/newer version of this object it might
// vary in number of elements that were serialized, but the contract of the formatter
// is that exactly one data structure must be read, regardless.
// Alternatively, we could check that the size of the array/map is what we expect
// and throw if it is not.
int count = reader.ReadArrayHeader();
for (int i = 0; i < count; i++)
{
switch (i)
{
case 0:
fullName = reader.ReadString();
break;
case 1:
age = reader.ReadInt32();
break;
default:
reader.Skip();
break;
}
}
reader.Depth--;
return new MySpecialObject(fullName, age);
}
}
団結サポート
サポートされる Unity の最小バージョンは 2018.3 で、API 互換性レベルは .NET 4.x と .NET Standard 2.0 の両方をサポートします。
Unitypackage はリリースページからインストールできます。ビルドが .NET Framework 4.x をターゲットにしており、mono で実行されている場合は、それを直接使用できます。ただし、ビルド対象が IL2CPP の場合、Dynamic***Resolver は使用できないため、事前コード生成を使用する必要があります。「プリコード生成」セクションを参照してください。
MessagePack for C# には、もともと NuGet で提供されていた追加の System.*.dll ライブラリがいくつか含まれています。これらは Plugins フォルダーの下にあります。他のパッケージがこれらのライブラリを使用している場合 (System.Runtime.CompilerServices.Unsafe.dll を使用する Unity Collections パッケージなど)、競合を避けるために、プラグインの下にある DLL を削除します。
現在、CompositeResolver.Create は IL2Cpp では機能しないため、StaticCompositeResolver.Instance.Register を使用することをお勧めします。
Unity では、MessagePackSerializer は組み込みの拡張機能 UnityResolver を使用して、Vector2、Vector3、Vector4、Quaternion、Color、Bounds、Rect、AnimationCurve、Keyframe、Matrix4x4、Gradient、Color32、RectOffset、LayerMask、Vector2Int、Vector3Int、RangeInt、RectInt、 BoundsInt とその Nullable、配列およびリスト型のシリアル化。これはデフォルトで StandardResolver に含まれています。
C# 用の MessagePack には、安全でない拡張機能が追加されています。UnsafeBlitResolver は、構造体の配列の非常に高速だが安全ではないシリアル化/逆シリアル化を行うための特別なパーサーです。