LoginSignup
13
26

More than 3 years have passed since last update.

C#の標準シリアライズ・デシリアライズを簡単にまとめてみた

Posted at

まとめてみた

設定とか、何かしらのオブジェクトをざっと保存して、さっと読み込みたいなぁなんて思った時に、シリアライザーという言葉が目に付きました。

でもなんか色々ある...。
というわけでちょっと、簡単に使える感じにまとめてみました。

個人的には ReactiveProperty がシリアライズできる、できないみたいなところが重要です。
でも、そうなると XmlSerializer しか使えない。
Slim とかもできないみたいですけど、ドキュメントを漁っても ReactivePropertyのシリアライズに関する記事がない...。

探し方が悪い?
そういった使い方をしないとか?

なんちゃってプログラマーの私にはわからない...。

標準のシリアライザー達

  • XmlSerializer

    • 結構汎用的というか、使い勝手がいいイメージのあるシリアライザー
    • ReactiveProperty<T> とかもシリアライズできる。(他はなんかできなかった…。シリアライズはカスタムできるらしいので、何かしらこねこねすればいけるんでしょうか?)
    • 適用にプロパティを持ったクラスがあるなら、この子に放り込めばいい感じにしてくれる。安パイ的な存在。
    • 空のコンストラクタが必須。
  • BinaryFormatter

    • バイナリで高速。(でも場合によりけりてきな文言が目に付く...)
    • ReactivePropertyはシリアライズできない。
    • クラス属性に [Serializeble] を宣言する。
    • 空のコンストラクタが必須。
  • DataContractSerializer

    • 他ではできないDictionaryとか、ほとんどのオブジェクトをシリアライズできる。シリアライザーとしては強力な機能を持っているらしいです。
    • ReactivePropertyはシリアライズできない。
    • クラス属性に [DataContract] を宣言する。
    • プロパティには [DataMember] を付けないとシリアライズされない。Orderとかでシリアライズ順序を指定できる。
    • 空のコンストラクタがいらない。(シリアライズ時にコンストラクタが呼び出されない)
  • DataContractJsonSerializer

    • オブジェクトをJSON形式でシリアライズ・デシリアライズできる。
    • DataContractSerializerよりも柔軟性がある。
    • 後は、XMLとの相互変換するような機能がある。(インテリセンスのオーバーロードに出たのを見ただけで試してないですが…)
    • JSON.Netとかライブラリがあるようなのでそちらを使った方がよい?
    • ReactivePropertyはシリアライズできない。
  • XamlWriter

    • ButtonとかのUI要素をシリアライズできる。
    • 画面レイアウトの保存とかに使える?
  • XamlReader

    • ButtonとかのUI要素をデシリアライズできる。
    • 画面レイアウトの復元とかに使える?

以下、コードです。


using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Json;
using System.Windows;
using System.Windows.Markup;
using System.Xml;
using System.Xml.Serialization;

namespace Serializers
{
    public static class XLizer
    {
        /// <summary>
        /// <see cref="XmlWriter"/> のネームスペース設定
        /// </summary>
        private static XmlSerializerNamespaces xmlWriterEmptyNameSpace { get { var empty = new XmlSerializerNamespaces(); empty.Add("", ""); return empty; } }

        /// <summary>
        /// <see cref="XmlWriter"/> のシリアライズ設定
        /// </summary>
        private static XmlWriterSettings xmlWriterSettings { get { return new XmlWriterSettings { Indent = true }; } }

        /// <summary>
        /// <see cref="XmlReader"/> のデシリアライズ設定
        /// </summary>
        private static XmlReaderSettings xmlReaderSettings { get { return new XmlReaderSettings { CheckCharacters = false }; } }

        /// <summary>
        /// <see cref="DataContractJsonSerializer"/> のシリアライズ設定
        /// </summary>
        //private static DataContractJsonSerializerSettings dataContractJsonSerializerSettings { get { return new DataContractJsonSerializerSettings { }; } }

        /// <summary>
        /// <para><see cref="XmlSerializer"/> を使用して <see cref="object"/> をシリアライズします。</para>
        /// </summary>
        public static bool XmlSerialize<T>(string filePath, T dataObject)
        {
            try {

                using XmlWriter xmlWriter =
                    XmlWriter.Create(
                        filePath,
                        xmlWriterSettings);

                XmlSerializer xmlSerializer =
                    new XmlSerializer(
                        typeof(T));

                xmlSerializer.Serialize(
                    xmlWriter,
                    dataObject,
                    xmlWriterEmptyNameSpace);

            } catch {
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="XmlSerializer"/> を使用して <see cref="object"/> をデシリアライズします。</para>
        /// </summary>
        public static bool XmlDeserialize<T>(string filePath, out T dataObject)
        {
            try {

                using XmlReader xmlReader =
                    XmlReader.Create(
                        filePath,
                        xmlReaderSettings);

                XmlSerializer xmlSerializer =
                    new XmlSerializer(
                        typeof(T));

                var obj =
                    xmlSerializer.Deserialize(
                        xmlReader);

                dataObject = (T)obj;

            } catch {
                dataObject = default;
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="BinaryFormatter"/> を使用して <see cref="object"/> をシリアライズします。</para>
        /// <code>
        ///     <para>[<see cref="Serializable"/>]</para>
        ///     <para>class MyClass { ... }</para>
        /// </code>
        /// </summary>
        public static bool BinarySerialize<T>(string filePath, T dataObject)
        {
            try {

                using FileStream fileStream =
                    new FileStream(
                        filePath,
                        FileMode.Create);

                BinaryFormatter binaryFormatter =
                    new BinaryFormatter();

                binaryFormatter.Serialize(
                    fileStream,
                    dataObject);

            } catch {
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="BinaryFormatter"/> を使用して <see cref="object"/> をデシリアライズします。</para>
        /// </summary>
        public static bool BinaryDeserialize<T>(string filePath, out T dataObject)
        {
            try {

                using FileStream fileStream =
                    new FileStream(
                        filePath,
                        FileMode.Open);

                BinaryFormatter binaryFormatter =
                    new BinaryFormatter();

                var obj =
                    binaryFormatter.Deserialize(
                        fileStream);

                dataObject = (T)obj;

            } catch {
                dataObject = default;
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="DataContractSerializer"/> を使用して <see cref="object"/> をシリアライズします。</para>
        /// <code>
        ///     <para>[<see cref="DataContract"/>]</para>
        ///     <para>class MyClass { ... }</para>
        /// </code>
        /// <code>
        ///     <para>[<see cref="DataMember"/>]</para>
        ///     <para>string Field { ... }</para>
        /// </code>
        /// </summary>
        public static bool DataContractSerialize<T>(string filePath, T dataObject)
        {
            try {

                using XmlWriter xmlWriter =
                    XmlWriter.Create(
                        filePath,
                        xmlWriterSettings);

                DataContractSerializer dataContractSerializer =
                    new DataContractSerializer(
                        typeof(T));

                dataContractSerializer.WriteObject(
                    xmlWriter,
                    dataObject);

            } catch {
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="DataContractSerializer"/> を使用して <see cref="object"/> をシリアライズします。</para>
        /// </summary>
        public static bool DataContractDeserialize<T>(string filePath, out T dataObject)
        {
            try {

                using XmlReader xmlReader =
                    XmlReader.Create(
                        filePath,
                        xmlReaderSettings);

                DataContractSerializer dataContractSerializer =
                    new DataContractSerializer(
                        typeof(T));

                var obj =
                    dataContractSerializer.ReadObject(
                        xmlReader);

                dataObject = (T)obj;

            } catch {
                dataObject = default;
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="DataContractJsonSerializer"/> を使用して <see cref="object"/> をシリアライズします。</para>
        /// <code>
        ///     <para>[<see cref="DataContract"/>]</para>
        ///     <para>class MyClass { ... }</para>
        /// </code>
        /// <code>
        ///     <para>[<see cref="DataMember"/>]</para>
        ///     <para>string Field { ... }</para>
        /// </code>
        /// </summary>
        public static bool DataContractJsonSerialize<T>(string filePath, T dataObject)
        {
            try {

                using FileStream fileStream =
                    new FileStream(
                        filePath,
                        FileMode.Create);

                DataContractJsonSerializer dataContractJsonSerializer =
                    new DataContractJsonSerializer(
                        typeof(T));

                dataContractJsonSerializer.WriteObject(
                    fileStream,
                    dataObject);

            } catch {
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="DataContractJsonSerializer"/> を使用して <see cref="object"/> をデシリアライズします。</para>
        /// </summary>
        public static bool DataContractJsonDeserialize<T>(string filePath, out T dataObject)
        {
            try {

                using FileStream fileStream =
                    new FileStream(
                        filePath,
                        FileMode.Open);

                DataContractJsonSerializer dataContractJsonSerializer =
                    new DataContractJsonSerializer(
                        typeof(T));

                var obj =
                    dataContractJsonSerializer.ReadObject(
                        fileStream);

                dataObject = (T)obj;

            } catch {
                dataObject = default;
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="XamlWriter"/> を使用して <see cref="UIElement"/> をシリアライズします。</para>
        /// </summary>
        public static bool XamlSerialize<T>(string filePath, T uiElement)
        {
            try {

                //string xamlString =
                //    XamlWriter.Save(
                //        uiElement);

                //File.WriteAllText(
                //    filePath,
                //    xamlString);

                using XmlWriter xmlWriter =
                    XmlWriter.Create(
                        filePath,
                        xmlWriterSettings);

                XamlWriter.Save(
                    uiElement,
                    xmlWriter);

            } catch {
                return false;
            }
            return true;
        }

        /// <summary>
        /// <para><see cref="XamlReader"/> を使用して <see cref="UIElement"/> をデシリアライズします。</para>
        /// </summary>
        public static bool XamlDeserialize<T>(string filePath, out T uiElement)
        {
            try {

                //string xamlString =
                //    File.ReadAllText(
                //        filePath);

                //var obj =
                //    XamlReader.Parse(
                //        xamlString);

                //uiElement = (T)obj;

                using XmlReader xmlReader =
                    XmlReader.Create(
                        filePath);

                var obj =
                    XamlReader.Load(
                        xmlReader);

                uiElement = (T)obj;

            } catch {
                uiElement = default;
                return false;
            }
            return true;
        }
    }
}

まとめ

オブジェクトのシリアライズ・デシリアライズには色々ライブラリが出回ってるみたいですけど、最初のとっかかりとしてはやはり標準を使いたい。というわけなので簡単にまとめてみたわけですが...。
今どきWPFでシリアライズの話?もうやり尽くされてますわ。見たいな感じですよね...。(でも、ざっとまとまってるのがなかったから!)

おまけとして。後は、プロパティにつける属性なんかがあったりします。
属性とはなんぞや? という方は XmlElement とかでggると幸せになれるかもです。

ちなみに初投稿。お目汚し失礼しました('ω')ノ

13
26
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
26