2010年5月20日木曜日

[c++/cli] XmlSerializerを使って、複数の型のアイテムを収容したListを書き込むときの注意

ちょこっとはまったので、メモとしてアップしておきます。


c++/cliで、List<Parent^>^ のプロパティがあって、そのListにAddされるのが、Child1とかChild2等の型のインスタンスだったりする場合。
シリアライズしようとすると

    XmlSerializer ^serializer = gcnew XmlSerializer(Parent::typeid);

    XmlWriterSettings^ st = gcnew XmlWriterSettings();
    st->Indent = true;
    st->IndentChars = "\t";
    XmlWriter^ writer = XmlWriter::Create(filename, st);

    serializer->Serialize(writer, this);  // (1)

(1)のところで、実行時に

    'System.InvalidOperationException' のハンドルされていない例外が System.Xml.dll で発生しました。
   
    追加情報: XML ドキュメントを生成中にエラーが発生しました。

のようなエラーが出て失敗します。(メッセージはVS2008の時)

この場合、XmlSerializerをgcnewするときに、書きこむ可能性のあるクラスを全部登録しておくといけます。

    array<Type^>^extraTypes = gcnew array<Type^>(3);
    extraTypes[ 0 ] = Child1::typeid;
    extraTypes[ 1 ] = Child2::typeid;
    extraTypes[ 2 ] = Child3::typeid;
    XmlSerializer ^serializer = gcnew XmlSerializer(Parent::typeid, extraTypes);

XMLから戻す際も、XmlSerializerをgcnewするとき、同様の処理が必要です。

これでできるXMLは、
    <lstTest>
        <Parent xsi:type="Child1">
            <strTest>abcde</strTest>
        </Parent>
        <Parent xsi:type="Child2">
            <intTest>1234</intTest>
        </Parent>
    </lstTest>

となってちょっとかっこいいです。