12/23/2009

理由はわかっているけれど、やってしまう間違い

どうもJudaです。
今日はXMLシリアライズな話


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
using System.Xml.Serialization;

namespace SerializeDaemon
{
class Program
{
static void Main(string[] args)
{
XmlSerializer xmlSel = new XmlSerializer(typeof(Deamon));
StringWriter wStrm = new StringWriter();
Deamon hoge = new Deamon();
xmlSel.Serialize(wStrm, hoge);
Console.WriteLine(wStrm.ToString());
}
}
public class TestA : ISerializable
{
protected int m_id = 0;
public TestA() { }
public int Id
{
get { return m_id; }
set { m_id = value; }
}

#region ISerializable
protected TestA(SerializationInfo info, StreamingContext context)
{
m_id = info.GetInt32("Id");
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ID", m_id);
}

#endregion
}
public class TestB : TestA
{
public TestB() : base() { }
protected TestB(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class TestC : TestA
{
public TestC() : base() { }
protected TestC(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class Deamon : ISerializable
{
TestA m_id0;
public TestA Id0
{
get { return m_id0; }
set { m_id0 = value; }
}

TestA m_id1;
public TestA Id1
{
get { return m_id1; }
set { m_id1 = value; }
}

TestA m_id2;
public TestA Id2
{
get { return m_id2; }
set { m_id2 = value; }
}

public Deamon()
{
m_id0 = new TestA();
m_id0.Id = 100;
m_id1 = new TestB();
m_id1.Id = 4000;
m_id2 = new TestC();
m_id2.Id = 6000;
}
protected Deamon(SerializationInfo info, StreamingContext context)
{
m_id0 = (TestA)info.GetValue("ID0", typeof(TestA));
m_id1 = (TestA)info.GetValue("ID1", typeof(TestA));
m_id2 = (TestA)info.GetValue("ID2", typeof(TestA));
}

#region ISerializable

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ID0", m_id0);
info.AddValue("ID1", m_id1);
info.AddValue("ID2", m_id2);
}

#endregion
}
}

コンパイルは通るけれども、実行はできないソースコード。
問題点は、シリアライズ対象のクラスがもっている要素に継承クラスが代入されていること。これはシリアライズにおいて、とても大変な問題をはらんでいる。
サブクラスをシリアライズする方法なんてわからないのだから。
シリアライズという行為が現状を復元可能な形で保存することにあるときに、継承クラスかどうかの判定なんて誰がどうやってするんだろーって事で原理的に今は無理です。柔軟に対応しないといけないならば、むしろ別の方法でそれを実現する方法を探す方が賢いと思います。あるいはできるなら、それを教えてください。
とりあえずは素直にすべての要素が構造体で定義されているものをシリアライズするコンテナクラスとして使用しましょう。というお話です。

細かな点ですが、インターフェイスはコンストラクタを規定できないので、実はISerializableの実装はちゃんとコンストラクタを特別に作っておかないとダメです。
ややこしいですねー。

0 件のコメント:

コメントを投稿