我有一些遗留代码使用ArrayList来序列化数据,这产生了<anyType xsi:type="SomeType">
的xml类型。它们都共享相同的数据类型,因此毫无意义,并产生混乱的代码。
在反序列化时,除了在反序列化之前对xml进行预清理之外,还有什么优雅的方法可以将这种类型的数据强制到List中吗?
基本上,我想从转代码
[Serializable()]
public class SomeContainer
{
public ArrayList SomeDataList1
public ArrayList SomeDataList2
public ArrayList SomeDataList3
public ArrayList SomeDataList4
}
至
[Serializable()]
public class SomeContainer
{
public List<SomeType1> SomeDataList1
public List<SomeType2> SomeDataList2
public List<SomeType3> SomeDataList3
public List<SomeType4> SomeDataList4
}
所以我对ArrayList感兴趣->列出翻译,而不是容器。
如果用正确的XML属性标记类,则可以使SomeContainer
类模仿ArrayList
的行为来反序列化XML。
您可能不在乎,但如果您还希望类与ArrayList一样进行序列化,则需要让类实现IEnumerable
。
请参阅下面的示例以获得与ArrayList相同的完全序列化/反序列化。如果需要,可以删除IEnumerable
实现,您将看到序列化发生了更改。使用"进行反序列化;anyType";但是在没有实现IEnumerable
的情况下仍然可以工作。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace SomeNamespace
{
[XmlType(nameof(SomeContainer))]
[XmlInclude(typeof(SomeType))]
public class SomeContainer : IEnumerable
{
[XmlArrayItem(typeof(SomeType))]
public List<SomeType> SomeDataList = new List<SomeType>();
public void Add(object o)
{
SomeDataList.Add(o as SomeType);
}
public int Count()
{
return SomeDataList.Count;
}
public IEnumerator GetEnumerator()
{
return SomeDataList.GetEnumerator();
}
}
public class SomeType
{
public string Name { get; set; } = "SomeName";
}
class Program
{
static void Main()
{
SomeContainer s1 = new SomeContainer();
s1.SomeDataList.Add(new SomeType());
string tempPath = "c:\temp\test.xml";
XmlSerializer serializer = new XmlSerializer(typeof(SomeContainer));
// serialize
using (StreamWriter sw = new StreamWriter(tempPath))
{
serializer.Serialize(sw, s1);
}
/* Produces the following XML:
<?xml version="1.0" encoding="utf-8"?>
<SomeContainer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<anyType xsi:type="SomeType">
<Name>SomeName</Name>
</anyType>
</SomeContainer>
*/
// deserialize
SomeContainer s2;
using (StreamReader sr = new StreamReader(tempPath))
{
s2 = (SomeContainer)serializer.Deserialize(sr);
}
// check contents of s2 as you please
}
}
}
(@Flydog57的评论是对的,而且是在我打字的时候写的。(
关于我为Sean Skelly的回答留下的评论。
public class AnyList<T> : IEnumerable where T : class
{
List<T> holder = new List<T>();
public int Count()
{
return holder.Count;
}
public void Add(object objectToAdd)
{
T typedObjectToAdd = objectToAdd as T;
if (typedObjectToAdd != null)
{
holder.Add(typedObjectToAdd);
}
// If you can't guarantee the input data, should perhaps inform some data will be skipped.
}
public IEnumerator GetEnumerator()
{
return holder.GetEnumerator();
}
}
XmlInclude很重要,因为它可能会自己推导,也可能不会,而是通过XmlNode传递,这对自定义转换可能有用,也可能不有用。
[Serializable()]
[XmlInclude(typeof(SomeType1))]
[XmlInclude(typeof(SomeType2))]
[XmlInclude(typeof(SomeType3))]
[XmlInclude(typeof(SomeType4))]
public class SomeContainer
{
public AnyList<SomeType1> SomeDataList1
public AnyList<SomeType2> SomeDataList2
public AnyList<SomeType3> SomeDataList3
public AnyList<SomeType4> SomeDataList4
}
这已经足够干净了,这意味着一旦数据规范化,我就可以改回List。
如果C#有泛型属性会更好。