gpt4 book ai didi

c# - 一种通用列表反序列化类?

转载 作者:太空宇宙 更新时间:2023-11-03 19:36:10 24 4
gpt4 key购买 nike

好的,这是到目前为止的故事。

我已经可以使用 XmlSerializer 反序列化单个对象了,但反序列化列表被证明是一个真正令人头疼的问题。我开始尝试序列化 List<Foo>并且序列化程序序列化了多个 <Foo>根内的 XML 结构 <ArrayOfFoo>元素。这被证明是反序列化的问题,所以看起来我需要自己定义 'ArrayOfFoo' 元素。所以,我有一个类在工作,它是列表的“包装器”,如该程序所示:

using System;
using System.IO;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace XmlTester2
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("XML tester...");

string xml =
"<ItemList xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<Person i:type=\"PersonI2\">" + "<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" + "</Person>" +
"<Account i:type=\"AccountI2\">" + "<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" + "</Account>" +
"<Person i:type=\"PersonI2\">" + "<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" + "</Person>" + "</ItemList>";

XmlSerializer ser = new XmlSerializer(typeof(ItemList));

using (var reader = new StringReader(xml))
{
ItemList result = (ItemList)ser.Deserialize(reader);
}

Console.WriteLine("Break here and check 'result' in Quickwatch...");
Console.ReadKey();
}
}

[XmlRootAttribute(IsNullable = false)]
public class ItemList
{
[XmlElementAttribute("Person")]
public List<Person> Persons { get; set; }

[XmlElementAttribute("Account")]
public List<Account> Accounts { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "Person", Namespace = "")]
[XmlInclude(typeof(PersonI2))]
public class Person
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "PersonI2", Namespace = "")]
public class PersonI2 : Person
{
public string Field4 { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "Account", Namespace = "")]
[XmlInclude(typeof(AccountI2))]
public class Account
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "AccountI2", Namespace = "")]
public class AccountI2 : Account
{
public string Field4 { get; set; }
}
}

然而,这个“包装器”,ItemList ,仍然必须在其中手动定义所有可能包含的元素(在示例中,Person 和 Account)。真正理想的是拥有一个通用列表包装器类。我知道这有点希望,但有没有办法做到这一点?我正在考虑这些方面的事情(这不起作用,但只是给你一个大概的想法):

using System;
using System.IO;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace XmlTester3
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("XML tester...");

string xml =
"<ItemList xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<Person i:type=\"PersonI2\">" +
"<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" +
"<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" +
"</Person>" +
"<Person i:type=\"PersonI2\">" +
"<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" +
"<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" +
"</Person>" +
"</ItemList>";

XmlSerializer ser = new XmlSerializer(typeof(ItemList<Person>));

using (var reader = new StringReader(xml))
{
ItemList<Person> result = (ItemList<Person>)ser.Deserialize(reader);
}

Console.WriteLine("Break here and check 'result' in Quickwatch...");
Console.ReadKey();
}
}

[XmlRootAttribute(IsNullable = false)]
[XmlInclude(typeof(Person))]
[XmlInclude(typeof(PersonI2))]
[XmlInclude(typeof(Account))]
[XmlInclude(typeof(AccountI2))]
public class ItemList<T>
{
[XmlElementAttribute]
public List<T> Items { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "Person", Namespace = "")]
[XmlInclude(typeof(PersonI2))]
public class Person
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "PersonI2", Namespace = "")]
public class PersonI2 : Person
{
public string Field4 { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "Account", Namespace = "")]
[XmlInclude(typeof(AccountI2))]
public class Account
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}

[XmlTypeAttribute(AnonymousType = false, TypeName = "AccountI2", Namespace = "")]
public class AccountI2 : Account
{
public string Field4 { get; set; }
}
}

因此,在 ItemList 中传递的 XML 结构只能是一种类型,比如说 Person在这个例子中,我可以定义一个 ItemList<Person>这将允许我反序列化包含多个 Person 对象的列表?有任何想法吗?如有必要,我不介意必须标记 ItemList[XmlInclude...]对于 ItemList 的每种类型可能包含一个集合。

我猜这是可能的,我只是还没有想出具体方法? :-) 还是默认的 XmlSerializer 太挑剔了?

最佳答案

你可以很容易地做到这一点,只需实现 System.Xml.Serialization.IXmlSerializable界面。如果我这样做,我什至可能会在定义 T 的程序集中反射(reflect) T 的可能派生类型,并完全省略 [XmlInclude] 声明。这种方法真正的缺点是 XmlSerializers 的创建。您可能会考虑缓存它们。无论如何,只需在您的第二个示例中使用它,它就可以工作。

顺便说一句,你用 "i:type=\"PersonI2\""做的事情很有趣;解决这个问题的 Prop ;)

[XmlRootAttribute("ItemList", IsNullable = false)]
[XmlInclude(typeof(Person))]
[XmlInclude(typeof(PersonI2))]
[XmlInclude(typeof(Account))]
[XmlInclude(typeof(AccountI2))]
public class ItemList<T> : System.Xml.Serialization.IXmlSerializable
{
class Map : Dictionary<String, XmlSerializer>
{ public Map() : base(StringComparer.Ordinal) { } }

public List<T> Items { get; set; }

public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}

private string TypeName(Type t)
{
String typeName = t.Name;
foreach (XmlTypeAttribute a in t.GetCustomAttributes(typeof(XmlTypeAttribute), true))
if (!String.IsNullOrEmpty(a.TypeName))
typeName = a.TypeName;
return typeName;
}

private Map LoadSchema()
{
Map map = new Map();
foreach (XmlIncludeAttribute inc in typeof(ItemList<T>).GetCustomAttributes(typeof(XmlIncludeAttribute), true))
{
Type t = inc.Type;
if (typeof(T).IsAssignableFrom(t))
map.Add(TypeName(t), new XmlSerializer(t));
}
return map;
}

public void ReadXml(System.Xml.XmlReader reader)
{
Map map = LoadSchema();
int depth = reader.Depth;

List<T> items = new List<T>();
if (!reader.IsEmptyElement && reader.Read())
{
while (reader.Depth > depth)
{
items.Add((T)map[reader.LocalName].Deserialize(reader));
}
}
this.Items = items;
}

public void WriteXml(System.Xml.XmlWriter writer)
{
Map map = LoadSchema();
foreach (T item in this.Items)
{
map[TypeName(item.GetType())].Serialize(writer, item);
}
}
}

关于c# - 一种通用列表反序列化类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1477533/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com