【C#】【XML】C# でXMLシリアライズ・デシリアライズ ~ DataContractSerializerクラス ~

  ■ はじめに

https://dk521123.hatenablog.com/entry/22166698
で、XMLシリアライズ・デシリアライズを行ったが、
XmlSerializerクラスでは、Dictionary をシリアル化できない。

色々な方法があるようだが、DataContractSerializerクラスでやるのが
一番スマートそうなので、纏める。

 

  ■ DataContractSerializerクラス

 * .NET3.0 から

  使用上の注意

 * プロジェクトの参照設定に「System.Runtime.Serialization.dll」を追加する必要がある
 * シリアライズするクラスに[DataContract]属性を、フィールドに[DataMember]属性を付与する必要がある
  => DataMemberを付加させないと、シリアル化の対象にならない

  XmlSerializerクラスとの違い

 * HashtableやDictionaryなどもシリアル化できる
 * パフォーマンスもいいらしい
 => XmlSerializerクラスは、シリアル化効率が悪く、シリアル化できる型も限られる

 

  ■ その他

  Enumの場合

 * EnumMemberAttribute([EnumMember]) を使用する

 

  ■ サンプル

  例1

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      Person person = new Person()
      {
        Name = "Mike",
        Birthday = DateTime.Now,
        NumberOfFamily = 4,
        Memos = new Dictionary<int, string>()
        {
          { 1, "Hello"},
          { 2, "World!!"},
          { 3, "Thank you for everything!!"},
          { 4, "Ciao!"}
        }
      };

      var filePath = @"hello.xml";
      Write<Person>(person, filePath);

      var clonePerson = Read<Person>(filePath);
      this.label1.Text = string.Format("{0}\n{1}\n{2}\n", clonePerson.Name, clonePerson.Birthday, clonePerson.NumberOfFamily);
      foreach (var memo in clonePerson.Memos)
      {
        this.label1.Text = this.label1.Text + string.Format("\n{0} : {1}", memo.Key, memo.Value);
      }
    }
    private static T Read<T>(string filePath)
    {
      var serializer = new DataContractSerializer(typeof(T));
      using (var reader = XmlReader.Create(filePath))
      {
        return (T)serializer.ReadObject(reader);
      }
    }

    private static void Write<T>(T instace, string filePath)
    {
      var settings = new XmlWriterSettings
      {
        Encoding = new UTF8Encoding(false)
      };

      var serializer = new DataContractSerializer(typeof(T));
      using (var writer = XmlWriter.Create(filePath, settings))
      {
        serializer.WriteObject(writer, instace);
      }
    }
  }

  [DataContract]
  public class Person
  {
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public DateTime Birthday { get; set; }
    [DataMember]
    public int NumberOfFamily { get; set; }
    [DataMember]
    public Dictionary<int, string> Memos { get; set; }
  }
}
出力結果
Mike
2019/02/21 22:03:02
4
1 : Hello
2 : World!!
3 : Thank you for everything!!
4 : Ciao!

  例2

[DataContract]
public class Person
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public int Age { get; set; }

    public Person(string newName, int newAge)
    {
        this.Name = newName;
        this.Age = newAge;
    }
}

public static T Copy<T>(T source) where T : class
{
    T result = null;
    using (var ms = new System.IO.MemoryStream())
    {
         // Serializer the User object to the stream.
         DataContractSerializer ser = new DataContractSerializer(typeof(T));
         ser.WriteObject(ms, source);
         ms.Position = 0;
         result = ser.ReadObject(ms) as T;
    }
    return result;
}
シリアライズ
public static Stream Serialize<T>(T target) 
{
     var formatter = new BinaryFormatter();
     var stream = new MemoryStream();
     formatter.Serialize(stream, target);

     stream.Seek(0, SeekOrigin.Begin);
     return stream;
}
シリアライズ
public static T Deserialize<T>(Stream target) 
{
     var formatter = new BinaryFormatter();
     T returnValue = (T) formatter.Deserialize(target);

     return returnValue;
}

 

 

  関連記事

  XML関連

C#XMLファイルを扱うには ~ 入門編 ~
https://dk521123.hatenablog.com/entry/32868509
C#XMLシリアライズ・デシリアライズ ~ XmlSerializerクラス ~
https://dk521123.hatenablog.com/entry/22166698