いきなりソースコード
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; }
}
}