1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-06-21

いきなりソースコード

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のスーパークラスを作る
##例

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。


public class TestClasses : SerializableList<TestClass> 
{
    public TestClasses():base()
    {
        NamerFactory = new IndexNamerFactory<TestClass>("TestClasses", 1);
    }
}

というようにXmlのタグ名のクラス等で継承しコンストラクタで具象NamerFactoryを作る。
#全体


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; }
    }
}

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?