更好的IXmlSerializable格式?

我有一个接口IInput阻止XmlSerializer本地序列化类(因为它不喜欢接口)。 我发现了一个黑客/解决方法,它试图在反序列化时创建底层实现,然后将其转换回接口。 反序列化器知道底层实现,因为它被编码为AssemblyQualifiedName属性

为了利用这种技术,我必须实现IXmlSerializable,但只有1个属性真的需要帮助( II输入输入 ),我希望所有其他属性的行为就像它们是正常的一样。 这是我的类,它按预期工作,但似乎是一种非常混乱的方式获取普通XMLserializer可以序列化以符合IXmlSerialiable接口的类型。

是否存在某种“除x之外本地序列化所有属性”? 如果不是,我可以通过什么方式使其更具可读性和/或更少的复制和粘贴

 public class JobInput : IJobInput, IXmlSerializable { public int AgencyId { get; set; } public Guid ExternalId { get; set; } public string Requester { get; set; } public IInput Input { get; set; } public XmlSchema GetSchema() { return null; } public void ReadXml(XmlReader reader) { reader.MoveToContent(); reader.ReadStartElement(); if (!reader.IsEmptyElement) { reader.ReadStartElement("AgencyId"); var xmlSerializer = new XmlSerializer(AgencyId.GetType()); AgencyId = ((int)xmlSerializer.Deserialize(reader)); reader.ReadEndElement(); reader.ReadStartElement("ExternalId"); xmlSerializer = new XmlSerializer(ExternalId.GetType()); ExternalId = ((Guid)xmlSerializer.Deserialize(reader)); reader.ReadEndElement(); reader.ReadStartElement("Requester"); xmlSerializer = new XmlSerializer(typeof(string)); Requester = ((string)xmlSerializer.Deserialize(reader)); reader.ReadEndElement(); var type = Type.GetType(reader.GetAttribute("AssemblyQualifiedName"), true); reader.ReadStartElement("IInput"); xmlSerializer = new XmlSerializer(type); Input = ((IInput)xmlSerializer.Deserialize(reader)); reader.ReadEndElement(); reader.ReadEndElement(); } } public void WriteXml(XmlWriter writer) { writer.WriteStartElement("AgencyId"); var xmlSerializer = new XmlSerializer(AgencyId.GetType()); xmlSerializer.Serialize(writer, AgencyId); writer.WriteEndElement(); writer.WriteStartElement("ExternalId"); xmlSerializer = new XmlSerializer(ExternalId.GetType()); xmlSerializer.Serialize(writer, ExternalId); writer.WriteEndElement(); writer.WriteStartElement("Requester"); xmlSerializer = new XmlSerializer(Requester.GetType()); xmlSerializer.Serialize(writer, Requester); writer.WriteEndElement(); writer.WriteStartElement("IInput"); writer.WriteAttributeString("AssemblyQualifiedName", Input.GetType().AssemblyQualifiedName); xmlSerializer = new XmlSerializer(Input.GetType()); xmlSerializer.Serialize(writer, Input); writer.WriteEndElement(); } } 

是否可以使用通用函数来检测所有具体类型的类型并适当地序列化/反序列化。 我想要的东西

 public void WriteXml(XmlWriter writer) { GenericSerialize("AgencyId", AgencyId, writer); GenericSerialize("ExternalId", ExternalId, writer); GenericSerialize("Requester", Requester, writer); writer.WriteStartElement("IInput"); writer.WriteAttributeString("AssemblyQualifiedName", Input.GetType().AssemblyQualifiedName); xmlSerializer = new XmlSerializer(Input.GetType()); xmlSerializer.Serialize(writer, Input); writer.WriteEndElement(); } 

您可以使用[XmlAnyElement]向您的类添加XElement [] -valued属性,该属性处理无法自动序列化的属性的序列化和反序列化,如下所示:

 [XmlRoot(Namespace = JobInput.XmlNamespace)] [XmlType(Namespace = JobInput.XmlNamespace)] public class JobInput { const string XmlNamespace = ""; public int AgencyId { get; set; } public Guid ExternalId { get; set; } public string Requester { get; set; } [XmlIgnore] public IInput Input { get; set; } [XmlAnyElement] [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)] public XElement[] XmlCustomElements { get { var list = new List(); if (Input != null) list.Add(Input.SerializePolymorphicToXElement(XName.Get("Input", XmlNamespace))); // Add others as needed. return list.ToArray(); } set { if (value == null) return; this.Input = value.DeserializePolymorphicEntry(XName.Get("Input", XmlNamespace)); // Add others as needed. } } } 

您的标准属性现在将自动序列化,并且可以使用适当的类型通过嵌套调用XmlSerializer来半自动序列化您的自定义属性。 需要以下扩展方法:

 public static class XObjectExtensions { public static XmlSerializerNamespaces NoStandardXmlNamespaces() { var ns = new XmlSerializerNamespaces(); ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines. return ns; } public static object Deserialize(this XContainer element, Type type, XmlSerializer serializer) { using (var reader = element.CreateReader()) { return (serializer ?? new XmlSerializer(type)).Deserialize(reader); } } public static XElement SerializeToXElement(this T obj, XmlSerializerNamespaces ns, XmlSerializer serializer) { var doc = new XDocument(); using (var writer = doc.CreateWriter()) (serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns); var element = doc.Root; if (element != null) element.Remove(); return element; } const string TypeAttributeName = "AssemblyQualifiedName"; public static T DeserializePolymorphicEntry(this XElement[] arrayValue, XName name) { var element = arrayValue.Where(e => e.Name == name).FirstOrDefault(); return element.DeserializePolymorphic(name); } public static T DeserializePolymorphic(this XElement value, XName name) { if (value == null) return default(T); var typeName = (string)value.Attribute(TypeAttributeName); if (typeName == null) throw new InvalidOperationException(string.Format("Missing AssemblyQualifiedName for \"{0}\"", value.ToString())); var type = Type.GetType(typeName, true); // Throw on error return (T)value.Deserialize(type, XmlSerializerFactory.Create(type, name)); } public static XElement SerializePolymorphicToXElement(this T obj, XName name) { if (obj == null) return null; var element = obj.SerializeToXElement(XObjectExtensions.NoStandardXmlNamespaces(), XmlSerializerFactory.Create(obj.GetType(), name)); // Remove namespace attributes (they will be added back by the XmlWriter if needed) foreach (var attr in element.Attributes().Where(a => a.IsNamespaceDeclaration).ToList()) attr.Remove(); element.Add(new XAttribute("AssemblyQualifiedName", obj.GetType().AssemblyQualifiedName)); return element; } } public static class XmlSerializerFactory { static readonly object padlock; static readonly Dictionary, XmlSerializer> serializers; // An explicit static constructor enables fairly lazy initialization. static XmlSerializerFactory() { padlock = new object(); serializers = new Dictionary, XmlSerializer>(); } ///  /// Return a cached XmlSerializer for the given type and root name. ///  ///  ///  /// a cached XmlSerializer public static XmlSerializer Create(Type type, XName name) { // According to https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer%28v=vs.110%29.aspx // XmlSerializers created with new XmlSerializer(Type, XmlRootAttribute) must be cached in a hash table // to avoid a severe memory leak & performance hit. if (type == null) throw new ArgumentNullException(); if (name == null) return new XmlSerializer(type); lock (padlock) { XmlSerializer serializer; var key = Tuple.Create(type, name); if (!serializers.TryGetValue(key, out serializer)) serializers[key] = serializer = new XmlSerializer(type, new XmlRootAttribute { ElementName = name.LocalName, Namespace = name.NamespaceName }); return serializer; } } } 

这样做可以使您的类看起来更简单,并减少实现IXmlSerializable出错的可能性 – 但它确实需要一些可重用的基础结构。

原型小提琴 。

似乎我追求的是可能的

 public void GenericWriter(ref XmlWriter writer, string propertyName, T property) { writer.WriteStartElement(propertyName); var xmlSerializer = new XmlSerializer(typeof(T)); xmlSerializer.Serialize(writer, property); writer.WriteEndElement(); } 

对读者来说同样如此。 我最后使用ref以防万一。