将 XML 文档中的'object'(anyType)反序列化为特定对象类型



我有一些遗留代码使用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#有泛型属性会更好。

相关内容

最新更新