HIRASE CONNECTION WK

programming collection

目次

Blog 利用状況

ニュース

あわせて読みたいブログパーツ

書庫

日記カテゴリ

Link Collection

[C#] 自分でオブジェクトをシリアライズ/デシリアライズする。

昨日に続き、実験。XmlSerializerを自前で実装してみます(簡易ですけど)。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;

namespace Sample
{
    internal class Program
    {

        private static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            mc.Value = "ぴょんぴょん";
            Serialize(mc, @"D:\hoge.xml");
            IEnumerable<Object> deserializedObjects = DeserializeObjects(@"D:\hoge.xml");
            foreach (object deserializedObject in deserializedObjects)
            {
                if (deserializedObject is MyClass)
                {
                    MyClass mc2 = deserializedObject as MyClass;
                    Debug.Assert(String.Equals(mc.Value, mc2.Value));
                }
            }
        }

        /// <summary>
        /// オブジェクトをファイルにシリアライズします。
        /// </summary>
        /// <param name="o">シリアライズするオブジェクト</param>
        /// <param name="filePath">ファイル名</param>
        public static void Serialize(Object o, String filePath)
        {
            using (StreamWriter streamWriter = new StreamWriter(filePath, false, Encoding.UTF8))
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(streamWriter))
                {
                    Type type = o.GetType();
                    xmlWriter.WriteStartElement("class");
                    xmlWriter.WriteAttributeString("type", type.FullName);

                    ForEachPropertyInfo(type, delegate(PropertyInfo propertyInfo)
                        {
                            if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
                                return;

                            Object propertyValue;
                            propertyValue = type.InvokeMember(propertyInfo.Name,
                                                              BindingFlags.GetProperty, null, o, null,
                                                              CultureInfo.CurrentCulture);
                            xmlWriter.WriteAttributeString(propertyInfo.Name, propertyValue.ToString());
                        });
                    xmlWriter.WriteEndElement();
                }
            }
        }

        /// <summary>
        /// ファイルに所定のフォーマットでシリアライズされたデータを
        /// デシリアライズします。
        /// </summary>
        /// <param name="filePath">ファイル名</param>
        public static IEnumerable<Object> DeserializeObjects(String filePath)
        {
            using (StreamReader streamReader = new StreamReader(filePath, Encoding.UTF8, true))
            {
                using (XmlReader xmlReader = XmlReader.Create(streamReader))
                {
                    while (xmlReader.Read())
                    {
                        if (!xmlReader.Name.Equals("class"))
                            continue;

                        String typeName = xmlReader.GetAttribute("type");
                        Type type = Type.GetType(typeName);
                        Object instance = Activator.CreateInstance(type);

                        ForEachPropertyInfo(type, delegate(PropertyInfo propertyInfo)
                            {
                                if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
                                    return;
                                String value = xmlReader.GetAttribute(propertyInfo.Name);
                                type.InvokeMember(propertyInfo.Name,
                                                  BindingFlags.SetProperty, null, instance, new Object[] {value},
                                                  CultureInfo.CurrentCulture);
                            });

                        yield return instance;
                    }
                }
            }
        }

        /// <summary>
        /// 指定した型に含まれるプロパティを全て列挙し、Actionerに渡す。
        /// </summary>
        /// <param name="type">プロパティを列挙したい型</param>
        /// <param name="Actioner">各プロパティを処理するPropertyInfoActioner</param>
        private static void ForEachPropertyInfo(Type type, PropertyInfoActioner Actioner)
        {
            foreach (PropertyInfo propertyInfo in type.GetProperties())
            {
                Actioner(propertyInfo);
            }
        }
        private delegate void PropertyInfoActioner(PropertyInfo propertyInfo);

        #region Nested type: MyClass
        /// <summary>
        /// (テスト用)シリアライズするクラス
        /// </summary>
        private class MyClass
        {
            private String value;

            public String Value
            {
                get { return value; }
                set { this.value = value; }
            }
        }
        #endregion
    }
}

投稿日時 : 2008年3月27日 2:01

コメントを追加

No comments posted yet.
タイトル  
名前  
URL
コメント