Ktouth Brand. on Web

け〜くんこと K.Ktouth のだらだらした日常と突発的に作るプログラムや読み物とかの雑多サイト



[2014年07月13日]

DataContract(IXmlSerializable) を使ってシリアライズ

2014年07月15日 21:03更新 筆者:K.Ktouth

Catel のお勉強中。
このライブラリは色々と便利な機能が詰まっているんだけど、公式以外の情報が少なくてねぇ……(ぉぃ 色々と説明を読まないとやっていけません(笑)
つー事でまず一番に確認する必要があると思っていたシリアライズ関連をチェック中です。Catel のシリアライズ機能は ModelBase および SavableModelBase<T> から派生したクラスなら自由にXML形式に(限定的にバイナリにも)出力、および入力が可能というもの。もちろん .NET 標準シリアライズ機能の DataContract を内部的に使用しているのでそれにさえ対応していれば自由に保存が出来るらしいです。

そこでまず、単純なクラスを IXmlSerializable インターフェイスを使った DataContract 対応データモデルを試しに作ってみた。単純な DataContract / DataMember 属性だと参照専用プロパティやXMLアトリビュート指定が出来ないので、この方が楽と思われます(笑) アトリビュートなら順番関係ないっぽいし。

using Catel.Data;
using System.Xml.Serialization;

class Entry : ObservableObject, IXmlSerializable
{
  public Entry(string name, DateTime lastUpdated) : base() { Name = name; LastUpdated = lastUpdated; }

  public string Name { get; private set; }
  public DateTime LastUpdated { get; private set; }

  #region IXmlSerializable インターフェイス

  System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { return null; }
  void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
  {
    if (reader.HasAttributes)
    {
      this.Name = reader.GetAttribute("Name");
      DateTime buf;
      if (DateTime.TryParse(reader.GetAttribute("LastUpdated"), out buf)) { this.LastUpdated = buf; }
    }
  }

  void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
  {
    writer.WriteAttributeString("Name", this.Name);
    writer.WriteAttributeString("LastUpdated", this.LastUpdated.ToLocalTime().ToString());
  }

  #endregion
}

んで、以下のコードがテストコード。

using NUnit.Framework;
using System.Xml.Linq;

[TestFixture]
class EntryTest
{
  [TestCase]
  public void シリアライズが正しく機能する()
  {
    var entry = new Entry("Sample<Name>", DateTime.Now.AddMinutes(-153.152546));
    using(var stream = new System.IO.MemoryStream())
    {
      var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(Entry));
      serializer.WriteObject(stream, entry);

      stream.Seek(0, System.IO.SeekOrigin.Begin);
      var root = XDocument.Load(stream).Root;
      Assert.That(root.Name.LocalName, Is.EqualTo(typeof(Entry).Name));
      Assert.That(root.Attribute("Name").Value, Is.EqualTo(entry.Name));
      Assert.That(root.Attribute("LastUpdated").Value, Is.EqualTo(entry.LastUpdated.ToString()));

      stream.Seek(0, System.IO.SeekOrigin.Begin);
      var restore = serializer.ReadObject(stream) as Entry;
      Assert.That(restore, Is.Not.Null);
      Assert.That(restore.Name, Is.EqualTo(entry.Name));
      Assert.That(restore.LastUpdated.ToString(), Is.EqualTo(entry.LastUpdated.ToString()));
    }
  }
}

コレで意図通りの出力が出来ました♪
が…… Catel のシリアライザを使おうとすると……なんかうまくリストアしてくれねぇ……げー

本日のリンク元
その他のリンク元
検索