[C#]ListをXmlSerializeするのに便利なクラス(Tag命名規則が柔軟に行える)

# いきなりソースコード
``` C#
public interface INamerFactory<T>
{
    INamer<T> Create();
}
public interface INamer<T>
{
    void Init();
    string NextName(T obj);
    string NextName();
}
 public abstract class SerializableList<T> : List<T>, IXmlSerializable
    {
        protected INamerFactory<T> NamerFactory { get; set; } = null;

        public SerializableList() : base()
        {
            NamerFactory = MakeNamerFactory();
        }

        protected abstract INamerFactory<T> MakeNamerFactory();

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {   
            reader.ReadStartElement();
            try
            {
                var namer = NamerFactory.Create();
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    var serializer = CreateSerializer(namer.NextName());
                    var item = (T)serializer.Deserialize(reader);
                    Add(item);
                }
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            var namer = NamerFactory.Create();

            var ns = new XmlSerializerNamespaces();
            ns.Add(String.Empty, String.Empty);
            foreach (var item in this)
            { 
                var serializer = CreateSerializer(namer.NextName());
                serializer.Serialize(writer, item, ns);
            }
        }
```
# 使い方
INamerFactoryを継承した具象NamerFactoryを作って、それを使うようにSerializableListのスーパークラスを作る
##例
``` C#
public class IndexNamerFactory<T> : INamerFactory<T>
    {
        protected string BaseName { get; set; }
        protected int StartIndex { get; set; }
        public IndexNamerFactory(string baseName,int startIndex = 0)
        {
            BaseName = baseName;
            StartIndex = startIndex;
        }

        public INamer<T> Create()
        {
            return new IndexNamer(BaseName, StartIndex);
        }

        public class IndexNamer : INamer<T>
        {
            private string BaseName { get; set; }
            private int StartIndex { get; set; }
            private int Index { get; set; }
            public IndexNamer(string baseName,int startIndex)
            {
                BaseName = baseName;
                StartIndex = startIndex;

                Init();
            }

            public void Init()
            {
                Index = StartIndex; 
            }

            public string NextName(T obj)
            {
                return NextName();
            }

            public string NextName()
            {
                var name = BaseName + Index.ToString();
                Index++;
                return name;
            }
        }
    }
```
を作って、これはIndexをつけながら命名していくNamerを作るFactory。

```C#

public class TestClasses : SerializableList<TestClass> 
{
    public TestClasses():base()
    {
        NamerFactory = new IndexNamerFactory<TestClass>("TestClasses", 1);
    }
}
```
というようにXmlのタグ名のクラス等で継承しコンストラクタで具象NamerFactoryを作る。
#全体
``` C#

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml.Schema;
using System.Xml;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var test1 = new TestClass()
            {
                Str = "ahoaho1",
                Id = 0,
                Bool = false,
                subClass = new TestSubClass() { A = "a" },
            };
            var test2 = new TestClass()
            {
                Str = "ahoaho2",
                Id = 1,
                Bool = false,
                subClass = new TestSubClass() { A = "b" },
            };

            var tests = new TestClasses();
            tests.Add(test1);
            tests.Add(test2);

            var m = new Main()
            {
                classes = tests,
            };


            var writer = new StringWriter();
            var serializer = new XmlSerializer(typeof(Main));

            serializer.Serialize(writer, m);

            var xml = writer.ToString();
            Console.WriteLine(xml);

            var tests_ = (Main)serializer.Deserialize(new StringReader(xml));

            writer.Flush();
            serializer.Serialize(writer, tests_);

            Console.WriteLine(writer.ToString());
        }

    }
    public interface INamerFactory<T>
    {
        INamer<T> Create();
    }
    public interface INamer<T>
    {
        void Init();
        string NextName(T obj);
        string NextName();
    }

    public class UniformNamerFactory<T> : INamerFactory<T>
    {
        protected string Name { get; set; }
        public INamer<T> Create()
        {
            return new UniformNamer(Name);
        }

        public class UniformNamer : INamer<T>
        {
            private readonly string Name;
            internal UniformNamer(string name)
            {
                Name = name;
            }
            public void Init()
            {
            }

            public string NextName(T obj)
            {
                return NextName();
            }

            public string NextName()
            {
                return Name;
            }
        }
    }

    public class IndexNamerFactory<T> : INamerFactory<T>
    {
        protected string BaseName { get; set; }
        protected int StartIndex { get; set; }
        public IndexNamerFactory(string baseName,int startIndex = 0)
        {
            BaseName = baseName;
            StartIndex = startIndex;
        }

        public INamer<T> Create()
        {
            return new IndexNamer(BaseName, StartIndex);
        }

        public class IndexNamer : INamer<T>
        {
            private string BaseName { get; set; }
            private int StartIndex { get; set; }
            private int Index { get; set; }
            public IndexNamer(string baseName,int startIndex)
            {
                BaseName = baseName;
                StartIndex = startIndex;

                Init();
            }

            public void Init()
            {
                Index = StartIndex; 
            }

            public string NextName(T obj)
            {
                return NextName();
            }

            public string NextName()
            {
                var name = BaseName + Index.ToString();
                Index++;
                return name;
            }
        }
    }


    public abstract class SerializableList<T> : List<T>, IXmlSerializable
    {
        protected INamerFactory<T> NamerFactory { get; set; } = null;

        public SerializableList() : base()
        {
            NamerFactory = MakeNamerFactory();
        }

        protected abstract INamerFactory<T> MakeNamerFactory();

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {   
            reader.ReadStartElement();
            try
            {
                var namer = NamerFactory.Create();
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    var serializer = CreateSerializer(namer.NextName());
                    var item = (T)serializer.Deserialize(reader);
                    Add(item);
                }
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            var namer = NamerFactory.Create();

            var ns = new XmlSerializerNamespaces();
            ns.Add(String.Empty, String.Empty);
            foreach (var item in this)
            { 
                var serializer = CreateSerializer(namer.NextName());
                serializer.Serialize(writer, item, ns);
            }
        }

        XmlSerializer CreateSerializer(string elementName)
        {
            // Create an XmlAttributes to override the default root element.
            var myXmlAttributes = new XmlAttributes();
            // Create an XmlRootAttribute and set its element name and namespace.
            var myXmlRootAttribute = new XmlRootAttribute()
            {
                ElementName = elementName,
            };
            // Set the XmlRoot property to the XmlRoot object.
            myXmlAttributes.XmlRoot = myXmlRootAttribute;
            var myXmlAttributeOverrides = new XmlAttributeOverrides();
            /* Add the XmlAttributes object to the 
            XmlAttributeOverrides object. */
            myXmlAttributeOverrides.Add(typeof(T), myXmlAttributes);

            return new XmlSerializer(typeof(T), myXmlAttributeOverrides);
        }
    }

    public class Main
    {
        public TestClasses classes { get; set; }
    }

    public class TestClasses : SerializableList<TestClass> 
    {
        protected override INamerFactory<TestClass> MakeNamerFactory()
        {
            return new IndexNamerFactory<TestClass>("TestClasses", 1);
        }
    }

    public class TestClass
    {
        public string Str { get; set; }

        public uint Id { get; set; }
        public bool Bool { get; set; }

        public TestSubClass subClass { get; set; }

        public string GetTag()
        {
            return "TestClass";
        }
    }

    public class TestSubClass
    {
        public string A { get; set; }
    }
}

```