经过一段时间的摆弄后,我想出了一个解决方案,并在这里发布以帮助处于相同情况的其他人。
首先,找到类型层次结构中的所有类型。然后编写一个函数来构建XmlElements
包含所有这些类型的实例:
XmlAttributes CreateXmlAttributesForHierarchyTypes()
{
return XmlAttributes
{
XmlElements =
{
new XmlElementAttribute("t", typeof (TType)),
new XmlElementAttribute("p", typeof (PType)),
new XmlElementAttribute("s", typeof (SType)),
new XmlElementAttribute("a", typeof (AType)),
new XmlElementAttribute("u", typeof (UType)),
}
};
}
现在找到具有您希望序列化的上述类型之一的字段的所有类型。您可以通过反映程序集中的所有类来做到这一点,但就我而言,我碰巧知道只有少数类具有此要求:
Type [] typesToOverride = new Type[]
{
typeof(PType),
typeof(SType),
typeof(AType),
typeof(UType),
typeof(ItemCollection),
};
我们现在继续创建一个实例XmlAttributeOverrides
指定了hierarchyTypeElements
覆盖适当类型的每个字段:
public static XmlAttributeOverrides GetAttributeOverrides(IEnumerable<Type> typesToOverride)
{
var overrides = typesToOverride
.SelectMany(x => x.GetFields()) // Get a flat list of fields from all the types
.Where(f => f.FieldType == typeof (BaseType)) // Must have the right type
.Select(f => new
{
Field = f,
Attributes = GetXmlAttributes(f)
})
.Where(f => f.Attributes != null)
.Aggregate(
new XmlAttributeOverrides(),
(ov, field) =>
{
ov.Add(field.Field.DeclaringType, field.Field.Name, field.Attributes);
return ov;
});
return overrides;
}
(是啊,我滥用Aggregate
; LinQ 真是一把简洁的金锤子)
最后使用XmlAttributeOverrides
创建序列化器的实例:
var attrOverrides = GetAttributeOverrides(TypesToDecorate);
serializer = new XmlSerializer(typeof(ItemCollection), attrOverrides);
您可能希望将该序列化程序缓存在静态变量中以避免泄漏程序集。
这段代码可以推广到修饰属性和字段。这留给读者作为练习。