C#　Dictionaryクラスを内包したクラスをシリアル化する方法


お世話になります。

Dictionaryを内包したクラスをシリアル化する方法を教えてください。  
ネットでも検索しましたが、ちょゅっと複雑で理解できませんでした。

お手数ではありますが、サンプルを踏まえて教えていただければ助かります。

下記の様なクラスです。

[code]

    public class Page
    {
        public string name = null;
        public Dictionary<string ,HashSet<string> dic = new Dictionary<string ,HashSet<string>>();
    
    }
    
[/code]

本当に申し訳ありませんが、これだけのクラスです。  
Dictionaryにstringが一つついただけですが、このクラスの  
シリアル化、逆シリアル化をお願いいたします。




単純な、同一環境への永続化や、同一アーキテクチャの別環境への転送と言うことであれば、BinaryFormatterを使うのが一番簡単かと思います。

欠点としては、バイナリへのシリアライズを行うので、シリアライズ結果の単純な目視確認が難しいという点と、例えば受信先の環境が異なる場合は、対処が難しい点です。

以下のサンプルはファイルストリームにシリアライズして、そこからデシリアライズするものです。

[code]

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace ConsoleApplication8
    {
        //この属性を付与する
        [Serializable]
        public class Page
        {
            public Dictionary<string, HashSet<string>> Dict = new Dictionary<string, HashSet<string>>();
            public string Name;
        }
    
    
        internal class Program
        {
            private static void Main()
            {
                //とりあえず作成。
                Page page = new Page {Name = "name"};
                page.Dict.Add("foo", new HashSet<string> {"hello", "world"});
                page.Dict.Add("bar", new HashSet<string> {"piyo"});
    
                //フォーマッタの初期化
                BinaryFormatter formatter = new BinaryFormatter();
    
                //シリアライズ
                using (FileStream fileStr = new FileStream("Page.bin", FileMode.Create))
                {
                    formatter.Serialize(fileStr, page);
                }
    
                Page deserializedObject;
                //デシリアライズ
                using (FileStream fileStr = new FileStream("Page.bin", FileMode.Open))
                {
                    deserializedObject = formatter.Deserialize(fileStr) as Page;
                }
    
    
                //蛇足的に。デシリアライズ後のPageオブジェクトの表示をしてみる。
                if (deserializedObject == null) Console.WriteLine("Fail!");
                else
                {
                    Console.WriteLine("Name:" + deserializedObject.Name);
                    Console.WriteLine();
    
                    foreach (KeyValuePair<string, HashSet<string>> pair in deserializedObject.Dict)
                    {
                        Console.WriteLine("Key:" + pair.Key);
                        foreach (string element in pair.Value)
                        {
                            Console.WriteLine("\tSetValue:" + element);
                        }
                        Console.WriteLine();
                    }
                }
    
                Console.WriteLine();
                Console.WriteLine("Press enter to exit...");
                Console.ReadLine();
            }
        }
    }
    
[/code]

もし、もっと汎用的なシリアライゼーションが必要であるなら、

  * Json.NET <https://www.nuget.org/packages/newtonsoft.json/>
  * MessagePack for CLI <https://www.nuget.org/packages/MsgPack.Cli>

などの外部シリアライザの運用を考慮してみても良いかも知れないです。  
尚、詳説は省きますが上記二つの外部シリアライザを使った場合のシリアライズと、デシリアライズの方法を簡単に書いておきます。（Nugetにて、適宜上記ライブラリを取得し参照しておいてください）

[code]

    using System;
    using System.Collections.Generic;
    using System.IO;
    using MsgPack;
    using Newtonsoft.Json;
    
    namespace ConsoleApplication8
    {
        public class Page
        {
            public Dictionary<string, HashSet<string>> Dict = new Dictionary<string, HashSet<string>>();
            public string Name;
        }
    
    
        internal class Program
        {
            private static void Main()
            {
                //とりあえず作成。
                Page page = new Page {Name = "Json.NET"};
                page.Dict.Add("foo", new HashSet<string> {"hello", "world"});
                page.Dict.Add("bar", new HashSet<string> {"piyo"});
    
                //Json.NETを使う場合。
                JsonSerializer jsonSerializer = new JsonSerializer();
    
    
                //シリアライズ
                using (StreamWriter wtr = new StreamWriter("page.json"))
                {
                    jsonSerializer.Serialize(wtr, page);
                }
    
                Page deserialized;
    
                //デシリアライズ
                using (JsonTextReader rdr = new JsonTextReader(new StreamReader("page.json")))
                {
                    deserialized = jsonSerializer.Deserialize<Page>(rdr);
                }
    
                //表示
                Console.WriteLine("Json sample");
                Dump(deserialized);
    
                Console.WriteLine();
                Console.WriteLine();
    
    
                //MessagePack for CLIを使う場合。
                page.Name = "MessagePack for CLI";
                page.Dict.Add("MsgPack", new HashSet<string> {"hoge", "piyo"});
    
                //シリアライズ
                using (FileStream str = new FileStream("page.msg", FileMode.Create))
                {
                    ObjectPacker packer = new ObjectPacker();
                    packer.Pack(str, page);
                }
    
                //デシリアライズ
                using (FileStream str = new FileStream("page.msg", FileMode.Open))
                {
                    ObjectPacker packer = new ObjectPacker();
                    deserialized = packer.Unpack<Page>(str);
                }
    
                //表示
                Console.WriteLine("MsgPack sample");
                Dump(deserialized);
            }
    
            public static void Dump(Page page)
            {
                Console.WriteLine("Name:" + page.Name);
                Console.WriteLine();
    
                foreach (var pair in page.Dict)
                {
                    Console.WriteLine("Key:" + pair.Key);
                    foreach (var elem in pair.Value)
                    {
                        Console.WriteLine("\tSetContent:" + elem);
                    }
                }
    
                Console.WriteLine();
            }
        }
    }
    
[/code]




単純な、同一環境への永続化や、同一アーキテクチャの別環境への転送と言うことであれば、BinaryFormatterを使うのが一番簡単かと思います。

欠点としては、バイナリへのシリアライズを行うので、シリアライズ結果の単純な目視確認が難しいという点と、例えば受信先の環境が異なる場合は、対処が難しい点です。

以下のサンプルはファイルストリームにシリアライズして、そこからデシリアライズするものです。

[code]

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace ConsoleApplication8
    {
        //この属性を付与する
        [Serializable]
        public class Page
        {
            public Dictionary<string, HashSet<string>> Dict = new Dictionary<string, HashSet<string>>();
            public string Name;
        }
    
    
        internal class Program
        {
            private static void Main()
            {
                //とりあえず作成。
                Page page = new Page {Name = "name"};
                page.Dict.Add("foo", new HashSet<string> {"hello", "world"});
                page.Dict.Add("bar", new HashSet<string> {"piyo"});
    
                //フォーマッタの初期化
                BinaryFormatter formatter = new BinaryFormatter();
    
                //シリアライズ
                using (FileStream fileStr = new FileStream("Page.bin", FileMode.Create))
                {
                    formatter.Serialize(fileStr, page);
                }
    
                Page deserializedObject;
                //デシリアライズ
                using (FileStream fileStr = new FileStream("Page.bin", FileMode.Open))
                {
                    deserializedObject = formatter.Deserialize(fileStr) as Page;
                }
    
    
                //蛇足的に。デシリアライズ後のPageオブジェクトの表示をしてみる。
                if (deserializedObject == null) Console.WriteLine("Fail!");
                else
                {
                    Console.WriteLine("Name:" + deserializedObject.Name);
                    Console.WriteLine();
    
                    foreach (KeyValuePair<string, HashSet<string>> pair in deserializedObject.Dict)
                    {
                        Console.WriteLine("Key:" + pair.Key);
                        foreach (string element in pair.Value)
                        {
                            Console.WriteLine("\tSetValue:" + element);
                        }
                        Console.WriteLine();
                    }
                }
    
                Console.WriteLine();
                Console.WriteLine("Press enter to exit...");
                Console.ReadLine();
            }
        }
    }
    
[/code]

もし、もっと汎用的なシリアライゼーションが必要であるなら、

  * Json.NET <https://www.nuget.org/packages/newtonsoft.json/>
  * MessagePack for CLI <https://www.nuget.org/packages/MsgPack.Cli>

などの外部シリアライザの運用を考慮してみても良いかも知れないです。  
尚、詳説は省きますが上記二つの外部シリアライザを使った場合のシリアライズと、デシリアライズの方法を簡単に書いておきます。（Nugetにて、適宜上記ライブラリを取得し参照しておいてください）

[code]

    using System;
    using System.Collections.Generic;
    using System.IO;
    using MsgPack;
    using Newtonsoft.Json;
    
    namespace ConsoleApplication8
    {
        public class Page
        {
            public Dictionary<string, HashSet<string>> Dict = new Dictionary<string, HashSet<string>>();
            public string Name;
        }
    
    
        internal class Program
        {
            private static void Main()
            {
                //とりあえず作成。
                Page page = new Page {Name = "Json.NET"};
                page.Dict.Add("foo", new HashSet<string> {"hello", "world"});
                page.Dict.Add("bar", new HashSet<string> {"piyo"});
    
                //Json.NETを使う場合。
                JsonSerializer jsonSerializer = new JsonSerializer();
    
    
                //シリアライズ
                using (StreamWriter wtr = new StreamWriter("page.json"))
                {
                    jsonSerializer.Serialize(wtr, page);
                }
    
                Page deserialized;
    
                //デシリアライズ
                using (JsonTextReader rdr = new JsonTextReader(new StreamReader("page.json")))
                {
                    deserialized = jsonSerializer.Deserialize<Page>(rdr);
                }
    
                //表示
                Console.WriteLine("Json sample");
                Dump(deserialized);
    
                Console.WriteLine();
                Console.WriteLine();
    
    
                //MessagePack for CLIを使う場合。
                page.Name = "MessagePack for CLI";
                page.Dict.Add("MsgPack", new HashSet<string> {"hoge", "piyo"});
    
                //シリアライズ
                using (FileStream str = new FileStream("page.msg", FileMode.Create))
                {
                    ObjectPacker packer = new ObjectPacker();
                    packer.Pack(str, page);
                }
    
                //デシリアライズ
                using (FileStream str = new FileStream("page.msg", FileMode.Open))
                {
                    ObjectPacker packer = new ObjectPacker();
                    deserialized = packer.Unpack<Page>(str);
                }
    
                //表示
                Console.WriteLine("MsgPack sample");
                Dump(deserialized);
            }
    
            public static void Dump(Page page)
            {
                Console.WriteLine("Name:" + page.Name);
                Console.WriteLine();
    
                foreach (var pair in page.Dict)
                {
                    Console.WriteLine("Key:" + pair.Key);
                    foreach (var elem in pair.Value)
                    {
                        Console.WriteLine("\tSetContent:" + elem);
                    }
                }
    
                Console.WriteLine();
            }
        }
    }
    
[/code]

