まえがき
MessagePack-CSharp(neuecc氏作)を使ってみたときに「はまったこと」「わかったこと」を記述していく
環境
IDE:VisualStudio2019
フレームワーク:.NET 5.0
基本的な使い方
using MessagePack;
using System;
namespace MessagePackTest
{
public class Program
{
// シリアル化させるオブジェクトには、MessagePackObject属性を付ける。
// 引数をtrueにするとプロパティの名前がそのまま使用される。
[MessagePackObject(true)]
public class MyClass
{
public string FirstName { get; set; } = "Hoge";
public string LastName { get; set; } = "Piyo";
// シリアル化させたくない場合には、[IgnoreMember]を付ける。
[IgnoreMember]
public string FullName { get { return FirstName + LastName; } }
}
static void Main()
{
var myClass1 = new MyClass();
// MessagePack形式のバイト配列に変換
byte[] bytes = MessagePackSerializer.Serialize(myClass1);
// 復元
MyClass myClass2 = MessagePackSerializer.Deserialize<MyClass>(bytes);
// JSONにも変換できる
var json = MessagePackSerializer.ConvertToJson(bytes);
Console.WriteLine(json);
}
}
}
出力結果
{"FirstName":"Hoge","LastName":"Piyo"}
基本的な使い方2
[Key(0)]のように数値を渡すと結果がArray形式になる
~略~
// シリアル化させるオブジェクトには、MessagePackObject属性を付ける。
// 引数をfalseにすると[Key()]を各プロパティに付ける必要がある。
[MessagePackObject(false)]
public class MyClass
{
[Key(0)]
public string FirstName { get; set; } = "Hoge";
[Key(1)]
public string LastName { get; set; } = "Piyo";
// シリアル化させたくない場合には、[IgnoreMember]を付ける。
[IgnoreMember]
public string FullName { get { return FirstName + LastName; } }
}
~略~
出力結果
["Hoge","Piyo"]
基本的な使い方3
[Key("FN")]のように文字列を渡すとMap形式になる
~略~
// シリアル化させるオブジェクトには、MessagePackObject属性を付ける。
// 引数をfalseにすると[Key()]を各プロパティに付ける必要がある。
[MessagePackObject(false)]
public class MyClass
{
[Key("FN")]
public string FirstName { get; set; } = "Hoge";
[Key("LN")]
public string LastName { get; set; } = "Piyo";
// シリアル化させたくない場合には、[IgnoreMember]を付ける。
[IgnoreMember]
public string FullName { get { return FirstName + LastName; } }
}
~略~
{"FN":"Hoge","LN":"Piyo"}
エラー例1
using MessagePack;
using System;
namespace MessagePackTest
{
class Program
{
static void Main(string[] args)
{
var mc = new MyClass
{
Age = 99,
FirstName = "hoge",
LastName = "huga",
};
byte[] bytes = MessagePackSerializer.Serialize(mc);
MyClass mc2 = MessagePackSerializer.Deserialize<MyClass>(bytes);
var json = MessagePackSerializer.ConvertToJson(bytes);
Console.WriteLine(json);
}
[MessagePackObject]
public class MyClass
{
[Key(0)]
public int Age { get; set; }
[Key(1)]
public string FirstName { get; set; }
[Key(2)]
public string LastName { get; set; }
[IgnoreMember]
public string FullName { get { return FirstName + LastName; } }
}
}
}
上記コードを実行すると、最初の Serialize 関数で以下の例外が発生する。
~略~
内部例外 1:
TypeInitializationException: The type initializer for 'FormatterCache`1' threw an exception.
内部例外 2:
TypeLoadException: Type 'MessagePack.Formatters.MessagePackTest_Program\+MyClassFormatter1' from assembly 'MessagePack.Resolvers.DynamicObjectResolver, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is attempting to implement an inaccessible interface.
「アクセスできないインターフェイスウンヌンカンヌン」とあるので
class Program が public じゃないのが悪かった。
MessagePack 自体の問題ではないけど、VisualStudioで自動生成された部分に間違いがあると思えずはまった。
継承したクラスの場合1
特に問題なく動作
using MessagePack;
using System;
namespace MessagePackTest
{
public class Program
{
static void Main(string[] args)
{
// {"Hoge":1,"Foo":10}
Console.WriteLine(MessagePackSerializer.SerializeToJson(new Sample4 { Foo = 10, Bar = 20, Hoge = 1 }));
}
[MessagePackObject(keyAsPropertyName: true)]
public class Sample4 : Base
{
public int Foo { get; set; }
[IgnoreMember]
public int Bar { get; set; }
}
[MessagePackObject(keyAsPropertyName: true)]
public class Base
{
public int Hoge { get; set; }
}
}
}
継承したクラスの場合2
- 上記のBaseのkeyAsPropertyNameをfalseにした場合
keyAsPropertyNameがtrueのときと同じ結果となった
他の部分略
[MessagePackObject(keyAsPropertyName: true)]
public class Sample4 : Base
{
public int Foo { get; set; }
[IgnoreMember]
public int Bar { get; set; }
}
[MessagePackObject]
public class Base
{
[Key(0)]
public int Hoge { get; set; }
}
継承したクラスの場合3
- 継承したクラスの場合1のSample4 のkeyAsPropertyNameをfalseにした場合
ビルドが失敗する(エラー内容は以下の出力)
BaseはkeyAsPropertyName=falseのつもりでも、継承先が優先されるため、[Key()]か[IgnoreMember]をつけろと怒られる
- Baseに[MessagePackObject]を付けなくても同様
他の部分略
[MessagePackObject]
public class Sample4 : Base
{
[Key(0)]
public int Foo { get; set; }
[IgnoreMember]
public int Bar { get; set; }
}
[MessagePackObject(keyAsPropertyName: true)]
public class Base
{
public int Hoge { get; set; }
}
出力
ビルドを開始しました...
1>------ ビルド開始: プロジェクト: MessagePackTest, 構成: Debug Any CPU ------
1>D:\Develop\TestProjects\MessagePackTest\MessagePackTest\Program.cs(138,24,138,28): error MsgPack004: Public members of MessagePackObject-attributed types require either KeyAttribute or IgnoreMemberAttribute. Sample4.Hoge.
1>プロジェクト "MessagePackTest.csproj" のビルドが終了しました -- 失敗。
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========
継承したクラスの場合4
- 継承したクラスの場合1のBaseにMessagePackObjectが無い場合
継承したクラスの場合1と同様
他の部分略
[MessagePackObject(keyAsPropertyName:true)]
public class Sample4 : Base
{
public int Foo { get; set; }
[IgnoreMember]
public int Bar { get; set; }
}
public class Base
{
public int Hoge { get; set; }
}