我有一个属性:如何序列类型对象的属性与XmlSerializer的
public object Tag
但它可以包含有限数量的类型,不幸的是无碱基类型(除对象类型)。但是当我用这个属性序列化对象时,它不会被序列化。有没有办法指示XmlSerializer可能的类型?
我有一个属性:如何序列类型对象的属性与XmlSerializer的
public object Tag
但它可以包含有限数量的类型,不幸的是无碱基类型(除对象类型)。但是当我用这个属性序列化对象时,它不会被序列化。有没有办法指示XmlSerializer可能的类型?
我并不推荐这样做,但是,是的,你可以使用[XmlElement]
等来告诉它的多个候选类型的成员:
public class Test
{
private static void Main()
{
var ser = new XmlSerializer(typeof (Test));
var obj = new Test {Value = "abc"};
ser.Serialize(Console.Out, obj);
obj = new Test { Value = 123 };
ser.Serialize(Console.Out, obj);
obj = new Test { Value = 456.7F };
ser.Serialize(Console.Out, obj);
}
[XmlElement("a", Type = typeof(int))]
[XmlElement("b", Type = typeof(string))]
[XmlElement("c", Type = typeof(float))]
public object Value { get; set; }
}
输出的重要位(忽略所有xmlns
/<?xml>
等)为:
<Test>
<b>abc</b>
</Test>
<Test>
<a>123</a>
</Test>
<Test>
<c>456.7</c>
</Test>
完美的作品! – user919426 2015-03-23 09:36:44
只有对元素使用不同的名称或名称空间时,这才有效(本例中为a,b,c)。就我而言,我需要元素名称始终相同,所以我发布了一个似乎适用于我的答案。 – Evan 2017-04-07 20:08:34
我做到了实现IXmlSerializable
接口,写对象类型作为元素属性。
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
Boolean isEmptyElement = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmptyElement)
{
// ...here comes all other properties deserialization
object tag;
if (ReadXmlObjectProperty(reader, "Tag", out tag))
{
Tag = tag;
}
reader.ReadEndElement();
}
}
public void WriteXml(XmlWriter writer)
{
// ...here comes all other properties serialization
WriteXmlObjectProperty(writer, "Tag", Tag);
}
public static bool ReadXmlObjectProperty(XmlReader reader,
string name,
out object value)
{
value = null;
// Moves to the element
while (!reader.IsStartElement(name))
{
return false;
}
// Get the serialized type
string typeName = reader.GetAttribute("Type");
Boolean isEmptyElement = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmptyElement)
{
Type type = Type.GetType(typeName);
if (type != null)
{
// Deserialize it
XmlSerializer serializer = new XmlSerializer(type);
value = serializer.Deserialize(reader);
}
else
{
// Type not found within this namespace: get the raw string!
string xmlTypeName = typeName.Substring(typeName.LastIndexOf('.')+1);
value = reader.ReadElementString(xmlTypeName);
}
reader.ReadEndElement();
}
return true;
}
public static void WriteXmlObjectProperty(XmlWriter writer,
string name,
object value)
{
if (value != null)
{
Type valueType = value.GetType();
writer.WriteStartElement(name);
writer.WriteAttributeString("Type", valueType.FullName);
writer.WriteRaw(ToXmlString(value, valueType));
writer.WriteFullEndElement();
}
}
public static string ToXmlString(object item, Type type)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.ASCII;
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
using(StringWriter textWriter = new StringWriter())
using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
XmlSerializer serializer = new XmlSerializer(type);
serializer.Serialize(xmlWriter, item, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
return textWriter.ToString();
}
}
注意:在代码中我没有使用命名空间和ASCII编码,这些都是非强制选择。
HTH, Cabbi
您还可以在的类,它包含的对象属性使用[XmlInclude(typeof(YourType))]
。因此,在OP的情况下,它看起来像这样
[XmlInclude(typeof(PossibleClassOne))]
[XmlInclude(typeof(PossibleClassTwo))]
public class MyClass
{
public object Tag { get; set; }
}
这样,您就可以保持你的元素名称<Tag>
在所有情况下
我期望你可以实现了ISerializable和控制的序列化对象取决于标签的类型,将其转换为可序列化的类型。但是我不知道你以后如何反序列化对象。序列化对象类型的东西可能不是一个好主意。 – 2012-02-29 10:31:15
@Adrian'XmlSerializer'不关心'ISerializable';然而,我同意坦率地说,这种情况最好简单地避免 – 2012-02-29 10:33:05
@Marc XmlSerializer并不关心ISerialiable,但它确实关心IXmlSerializable,并且会在实现它的对象上调用读写方法。 – Fen 2012-02-29 11:18:07