我最近使用 XMLSerializer 注册了未知节点、元素和属性的事件处理程序,用于从类型层次结构中反序列化复杂类型。我这样做是因为我收到的一些 XML 来自第三方;我对可能会给我带来麻烦的数据格式更改感兴趣。
在 XML 中,XMLSerializer 生成它使用标准 XML 属性xsi:type="somederivedtypename"
来识别由 XML 元素表示的实际派生类型。
我惊讶地发现,同一个序列化程序在反序列化时将它刚刚产生的相同属性视为未知。不过有趣的是,反序列化是正确且完整的(在我的实际程序中也有更复杂的类型和数据)。这意味着序列化程序在反序列化的早期阶段会正确评估类型信息。但是在后来的数据提取阶段,该属性显然被误认为是对象的真实数据部分,这当然是未知的。
在我的应用程序中,无端警告最终会弄乱一个不受欢迎的通用日志文件。在我看来,序列化程序应该读回它生成的 XML,而不会出现任何问题。我的问题:
- 难道我做错了什么?
- 有解决方法吗?
一个最小的例子在这里:
using System;
using System.IO;
using System.Xml.Serialization;
namespace XsiTypeAnomaly
{
/// <summary>
/// A trivial base type.
/// </summary>
[XmlInclude(typeof(DerivedT))]
public class BaseT{}
/// <summary>
/// A trivial derived type to demonstrate a serialization issue.
/// </summary>
public class DerivedT : BaseT
{
public int anInt { get; set; }
}
class Program
{
private static void serializer_UnknownAttribute
( object sender,
XmlAttributeEventArgs e )
{
Console.Error.WriteLine("Warning: Deserializing "
+ e.ObjectBeingDeserialized
+ ": Unknown attribute "
+ e.Attr.Name);
}
private static void serializer_UnknownNode(object sender, XmlNodeEventArgs e)
{
Console.Error.WriteLine("Warning: Deserializing "
+ e.ObjectBeingDeserialized
+ ": Unknown node "
+ e.Name);
}
private static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
Console.Error.WriteLine("Warning: Deserializing "
+ e.ObjectBeingDeserialized
+ ": Unknown element "
+ e.Element.Name);
}
/// <summary>
/// Serialize, display the xml, and deserialize a trivial object.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
BaseT aTypeObj = new DerivedT() { anInt = 1 };
using (MemoryStream stream = new MemoryStream())
{
var serializer = new XmlSerializer(typeof(BaseT));
// register event handlers for unknown XML bits
serializer.UnknownAttribute += serializer_UnknownAttribute;
serializer.UnknownElement += serializer_UnknownElement;
serializer.UnknownNode += serializer_UnknownNode;
serializer.Serialize(stream, aTypeObj);
stream.Flush();
// output the xml
stream.Position = 0;
Console.Write((new StreamReader(stream)).ReadToEnd() + Environment.NewLine);
stream.Position = 0;
var serResult = serializer.Deserialize(stream) as DerivedT;
Console.WriteLine(
(serResult.anInt == 1 ? "Successfully " : "Unsuccessfully ")
+ "read back object");
}
}
}
}
输出:
<?xml version="1.0"?>
<BaseT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="DerivedT">
<anInt>1</anInt>
</BaseT>
Warning: Deserializing XsiTypeAnomaly.DerivedT: Unknown node xsi:type
Warning: Deserializing XsiTypeAnomaly.DerivedT: Unknown attribute xsi:type
Successfully read back object