我最近使用XMLSerializer注册了未知节点、元素和属性的事件处理程序,我用它来反序列化类型层次结构中的复杂类型。我这样做是因为我收到的某些XML来自第三方;我对可能导致我的问题的数据格式变化感兴趣。
在XML中,XMLSerializer使用标准的XML属性xsi:type="somederivedtypename"来识别由XML元素表示的实际派生类型。
令人惊讶的是,同一个序列化器在反序列化时将刚刚生成的同一属性视为未知属性。有趣的是,反序列化是正确且完整的(也适用于我实际编程中更复杂的类型和数据)。这意味着序列化器在反序列化的早期阶段正确评估了类型信息。但在稍后的数据提取阶段,该属性显然被误认为是对象的真正数据部分,而该属性当然是未知的。
在我的应用程序中,无谓的警告会使通用日志文件混乱,这是不希望看到的。我认为序列化器应该能够毫无问题地读回它生成的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
BaseT
创建了一个序列化程序,然后实际上提供了一个DerivedT
对象。如果您只为DerivedT
创建一个序列化程序,则警告消失。 - jsanalyticsanInt
属性。建议:在创建序列化程序时,请使用aTypeObj.GetType()
而不是使用任何显式类型,无论是基础类型还是派生类型。 - jsanalyticsanInt
的;该元素已经被正确地序列化和反序列化(当我在反序列化后测试非默认值时可以看到)。警告是关于属性xsi:type
的。这些属性语法上可以携带对象信息(例如,我可以将anInt
序列化为属性!),但序列化器使用它们来存储有关类型的元信息。属性xmlns:xsi
和xmlns:xsd
被正确地识别为“不属于对象数据的一部分”,但xsi:type
却没有,我认为这是一个错误。 - Peter - Reinstate Monica