我有一个接口IInput,它阻止XmlSerializer本机序列化类(因为它不喜欢接口)。我找到了一个黑客/解决方案,试图在反序列化时创建底层实现,然后将其转换回接口。反序列化器知道底层实现,因为它被编码为属性AssemblyQualifiedName。
为了利用这一技术,我必须实现IXmlSerializable,但只有一个属性真正需要帮助(IInput Input),我希望其他所有属性都能正常工作。这是我的类,它像预期的那样工作,但似乎是获取类型的一种非常麻烦的方法,普通的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();
}发布于 2015-10-16 22:54:14
可以使用[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<XElement>();
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<IInput>(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<T>(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<T>(this XElement[] arrayValue, XName name)
{
var element = arrayValue.Where(e => e.Name == name).FirstOrDefault();
return element.DeserializePolymorphic<T>(name);
}
public static T DeserializePolymorphic<T>(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<T>(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<Tuple<Type, XName>, XmlSerializer> serializers;
// An explicit static constructor enables fairly lazy initialization.
static XmlSerializerFactory()
{
padlock = new object();
serializers = new Dictionary<Tuple<Type, XName>, XmlSerializer>();
}
/// <summary>
/// Return a cached XmlSerializer for the given type and root name.
/// </summary>
/// <param name="type"></param>
/// <param name="name"></param>
/// <returns>a cached XmlSerializer</returns>
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时出错的可能性--但它确实需要一点可重用的基础设施。
原型小提琴。
发布于 2015-10-17 05:21:03
似乎我想要的是可能的
public void GenericWriter<T>(ref XmlWriter writer, string propertyName, T property)
{
writer.WriteStartElement(propertyName);
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(writer, property);
writer.WriteEndElement();
}读者也一样。最后我用了裁判以防万一。
https://stackoverflow.com/questions/33163580
复制相似问题