我有一个属性:
public object Tag
但它可以包含有限数量的类型,遗憾的是没有基类型(对象类型除外)。但是,当我使用此属性序列化对象时,它不会被序列化。有没有办法用可能的类型指示XmlSerializer?
答案 0 :(得分:10)
我不建议这样做,但是,您可以使用[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>
答案 1 :(得分:1)
我实现了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
答案 2 :(得分:0)
您还可以在包含object属性的类上使用[XmlInclude(typeof(YourType))]
。所以在OP的情况下,它看起来像这样
[XmlInclude(typeof(PossibleClassOne))]
[XmlInclude(typeof(PossibleClassTwo))]
public class MyClass
{
public object Tag { get; set; }
}
这样,您可以在所有情况下保留元素名称<Tag>