いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-031 (シリアライズ-4)(OnSerializing, OnSerialized, OnDeserializing, OnDeserialized)


今回も、特定のタイミングにてコールバックされるメソッドについてです。


前回、IDeserializationCallbackインターフェースについて記述しましたが
これは、デシリアライズ後のみのコールバックでした。


.Net2.0以降は、もう少し実装が簡単になっていまして
以下の属性を付加することで細かいタイミングを制御できるようになっています。


上記の属性を付与するメソッドの書式は決まっていて
以下の書式となっています。

    [OnSerializing]
    void XXXXX(StreamingContext context)
    {
        .....
    }

また、前回のIDeserializationCallbackと同様に
上記のメソッドもXmlSerializerを利用して処理をおこなう場合には
呼ばれません。BinaryFormatterまたはSoapFormatterの場合に呼ばれます。


以下、サンプルです。

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace SerializationSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //
            // OnSerializing, OnSerialized
            // OnDeserializing, OnDeserialized
            // メソッドを実装した処理.
            //
            // 他のカスタムメソッドと同じく
            // XmlSerializerの場合はOnXXXXメソッドは呼ばれない。
            // (呼ばれるのは,BinaryFormatter等のRuntime Serializerのみ)
            //
            Console.WriteLine("============ (OnXXXXメソッド) ===========");

            Data4 data4 = new Data4
                {
                    Id = 1,
                    Name = "Name-1"
                };

            PrintXmlSerializedData(Console.Out, data4);
            WriteBinarySerializedData("Data4-DAT.xml", data4);
            PrintBinaryDeserializedData(typeof(Data4), "Data4-DAT.xml");

            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }

        #region Helper Methods
        private static void PrintXmlSerializedData(TextWriter writer, object data)
        {
            if (data == null)
            {
                return;
            }
            
            if (writer == null)
            {
                writer = Console.Out;
            }

            new XmlSerializer(data.GetType()).Serialize(writer, data);
            Console.WriteLine(string.Empty);
        }

        private static void WriteBinarySerializedData(string filePath, object data)
        {
            if (data == null)
            {
                return;
            }
            
            using (Stream writer = File.Open(filePath, FileMode.Create))
            {
                (new BinaryFormatter()).Serialize(writer, data);
                Console.WriteLine(string.Empty);
            }
        }

        private static void PrintBinaryDeserializedData(Type type, string filePath)
        {
            using (Stream reader = File.Open(filePath, FileMode.Open))
            {
                var data = new BinaryFormatter().Deserialize(reader);
                foreach (PropertyInfo propInfo in data.GetType().GetProperties())
                {
                    Console.WriteLine("{0}={1}", propInfo.Name, propInfo.GetValue(data, null));
                }
            }

        }
        #endregion
    }

    #region Sample Classes
    [Serializable]
    public class Data4
    {
        public int Id
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }

        //
        // OnSerializing属性を付加したメソッドが呼ばれるのは
        // BinaryFormatter等のRuntime Serializerを利用した場合のみ。
        // (XmlSerializerを利用している場合、このメソッドは呼ばれない。)
        //
        [OnSerializing]
        void OnSerializing(StreamingContext context)
        {            
            Console.WriteLine("OnSerializing={0},{1}", context.State, context.Context);
        }

        //
        // OnSerialized属性を付加したメソッドが呼ばれるのは
        // BinaryFormatter等のRuntime Serializerを利用した場合のみ。
        // (XmlSerializerを利用している場合、このメソッドは呼ばれない。)
        //
        [OnSerialized]
        void OnSerialized(StreamingContext context)
        {
            Console.WriteLine("OnSerialized={0},{1}", context.State, context.Context);
        }

        //
        // OnDeserializing属性を付加したメソッドが呼ばれるのは
        // BinaryFormatter等のRuntime Serializerを利用した場合のみ。
        // (XmlSerializerを利用している場合、このメソッドは呼ばれない。)
        //
        [OnDeserializing]
        void OnDeserializing(StreamingContext context)
        {
            Console.WriteLine("OnDeserializing={0},{1}", context.State, context.Context);
        }

        //
        // OnDeserialized属性を付加したメソッドが呼ばれるのは
        // BinaryFormatter等のRuntime Serializerを利用した場合のみ。
        // (XmlSerializerを利用している場合、このメソッドは呼ばれない。)
        //
        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            Console.WriteLine("OnDeserialized={0},{1}", context.State, context.Context);

            //
            // 値を強制的に変更.
            //
            Id += 100;
            Name = "Modified";
        }
    }
    #endregion
}

================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。