C++/CLIクラスのSerialization
C++/CLIでクラス作成したとき,アンマネージポインタをメンバに含む場合があります.このクラスをシリアライズするときは,ISerializableインタフェースを実装し,アンマネージの内容を明示的にシリアル化する必要があります(Serializable属性を付けるだけだと,ポインタの値がそのまま記録されてしまいます(たぶん)).
また,ISerializableインタフェースを実装すると,逆シリアル化の際の呼び出し順の関係上,既定の処理の前に,逆シリアル化用のprotectedコンストラクタが呼び出されてしまいます(シリアル化プロセスの手順:http://msdn2.microsoft.com/ja-jp/library/tyf8zbfk(VS.80).aspx).そのため,メンバ間に依存関係がある場合は,依存関係にある全てのメンバを,明示的にシリアル/逆シリアル化する必要があります.
[Serializable] public ref class Data : public Runtime::Serialization::ISerializable { protected: Data(Runtime::Serialization::SerializationInfo^ info, Runtime::Serialization::StreamingContext context) { this->Clear(); m_row = info->GetInt32(L"m_row"); m_col = info->GetInt32(L"m_col"); m_body = new double[m_row*m_col]; String^ str = info->GetString(L"m_body"); array<String^>^ elems = str->Split(gcnew array<Char> {','}); for(int i=0; i<m_row*m_col; ++i){ m_body[i] = double::Parse(elems[i]); } } public: virtual void GetObjectData(Runtime::Serialization::SerializationInfo^ info, Runtime::Serialization::StreamingContext context) { info->AddValue(L"m_row", m_row, m_row.GetType()); info->AddValue(L"m_col", m_col, m_col.GetType()); String^ str = ""; for(int i=0; i<m_row*m_col; ++i) str += (m_body[i].ToString() + *1; } void Clear() { if(m_body != nullptr){ delete[] m_body; m_body = nullptr; m_row = m_col = 0; } } // いろいろ... private: int m_row; int m_col; double* m_body; };
【補足】
シリアライズの仕組みは,Reflectionにより実現されています.
http://msdn2.microsoft.com/ja-jp/library/yz07hhw9(VS.80).aspx
MyData.Data dt = new MyData.Data(10, 10, -1); Type type = dt.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fd in fields) { object obj = fd.GetValue(dt); // ... }
こんな感じでしょうか.
【おまけ】
列挙子をOR演算子で連結したいときはFlagsAttributeを付ける.
http://msdn2.microsoft.com/ja-jp/library/system.flagsattribute(VS.80).aspx
*1:i<m_row*m_col-1)?(L","):(L""))); info->AddValue(L"m_body", str, str->GetType(