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(