您可以使用XmlSerializer
上的XmlSerializer.UnknownElement
事件來捕獲亂序元素。這將允許您手動查找並解決反序列化中的問題。
更復雜的答案是在序列化時正確排序元素,但在反序列化時忽略順序。這需要使用XmlAttributes
類和XmlSerializer(Type, XmlAttributeOverrides)
構造函數。請注意,以這種方式構建的串行器must be cached in a hash table and resused可避免嚴重的內存泄漏,因此此解決方案有點「挑剔」,因爲Microsoft不提供有意義的GetHashCode()
用於XmlAttributeOverrides
。下面是一個可能實現這取決於事先知道需要他們XmlElementAttribute.Order
和XmlArrayAttribute.Order
屬性忽略所有類型的,從而避免了需要創建一個複雜的自定義散列方法:
public class XmlSerializerFactory : XmlOrderFreeSerializerFactory
{
static readonly XmlSerializerFactory instance;
// Use a static constructor for lazy initialization.
private XmlSerializerFactory()
: base(new[] { typeof(Type2), typeof(Type1), typeof(TestClass), typeof(Type3) }) // These are the types in your client for which Order needs to be ignored whend deserializing
{
}
static XmlSerializerFactory()
{
instance = new XmlSerializerFactory();
}
public static XmlSerializerFactory Instance { get { return instance; } }
}
public abstract class XmlOrderFreeSerializerFactory
{
readonly XmlAttributeOverrides overrides;
readonly object locker = new object();
readonly Dictionary<Type, XmlSerializer> serializers = new Dictionary<Type, XmlSerializer>();
static void AddOverrideAttributes(Type type, XmlAttributeOverrides overrides)
{
if (type == null || type == typeof(object) || type.IsPrimitive || type == typeof(string))
return;
var mask = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
foreach (var member in type.GetProperties(mask).Cast<MemberInfo>().Union(type.GetFields(mask)))
{
XmlAttributes overrideAttr = null;
foreach (var attr in member.GetCustomAttributes<XmlElementAttribute>())
{
overrideAttr = overrideAttr ?? new XmlAttributes();
overrideAttr.XmlElements.Add(new XmlElementAttribute { DataType = attr.DataType, ElementName = attr.ElementName, Form = attr.Form, IsNullable = attr.IsNullable, Namespace = attr.Namespace, Type = attr.Type });
}
foreach (var attr in member.GetCustomAttributes<XmlArrayAttribute>())
{
overrideAttr = overrideAttr ?? new XmlAttributes();
overrideAttr.XmlArray = new XmlArrayAttribute { ElementName = attr.ElementName, Form = attr.Form, IsNullable = attr.IsNullable, Namespace = attr.Namespace };
}
if (overrideAttr != null)
overrides.Add(type, member.Name, overrideAttr);
}
}
protected XmlOrderFreeSerializerFactory(IEnumerable<Type> types)
{
overrides = new XmlAttributeOverrides();
foreach (var type in types.SelectMany(t => t.BaseTypesAndSelf()).Distinct())
{
AddOverrideAttributes(type, overrides);
}
}
public XmlSerializer GetSerializer(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
lock (locker)
{
XmlSerializer serializer;
if (!serializers.TryGetValue(type, out serializer))
serializers[type] = serializer = new XmlSerializer(type, overrides);
return serializer;
}
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
(注 - 只有部分測試。 )
然後,在反序列化類型時,使用工廠提供的XmlSerializer
。鑑於SoapEnvelope
是XmlDocument
的一個子類,您應該能夠按照Deserialize object property with StringReader vs XmlNodeReader中回答的行反序列化主體節點。
來源
2015-11-03 20:50:26
dbc
我真的希望這實際上是一個X-Y問題,並且有比檢查XmlSerializer更簡單的答案,但我並不期待它。 – Bobson
您可以使用['XmlSerializer.UnknownElement'](https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.unknownelement%28v=vs.110%29.aspx)。 – dbc
@dbc - Oooh,可以工作。這並不理想,但我絕對可以用它。當然,這種情況並不理想,所以我不應該感到驚訝。 – Bobson