【发布时间】:2017-03-22 15:21:49
【问题描述】:
我正在使用 .NET 4.52。我正在用 VB.NET 编程,但如果你有 C# 的解决方案,我可以转置。
我有一个完整的类库,其中有一堆复杂的类型等,它们代表我们系统中的不同消息,我无法更改。根据 Message_Type(XMLRoot 中的一个属性),需要不同的属性和元素。如果我尝试反序列化具有错误信息的对象,它不会抛出异常,我想要它。 XSD 验证不起作用,因为两种不同类型的元素名称通常相同,但每种类型需要不同的东西。在我的类上使用 XMLAttribute 和 XMLElement 标记,没有“必需”属性。尽管 Elements(但不是 Attributes)上有一个“IsNullable”属性,但 XMLSerializer 在反序列化过程中似乎没有注意这一点。
所以,我决定尝试创建一个额外的“必需”属性:
<AttributeUsage(AttributeTargets.Property, Inherited:=False, AllowMultiple:=False)>
Public Class XMLPlusElementAttribute
Inherits XmlElementAttribute
Public Sub New()
MyBase.ElementName = ElementName
Me.m_Required = False
End Sub
Private m_Required As Boolean
Public Overridable Property Required() As Boolean
Get
Return m_Required
End Get
Set(value As Boolean)
m_Required = value
End Set
End Property
End Class
<AttributeUsage(AttributeTargets.Property, Inherited:=False, AllowMultiple:=False)>
Public Class XMLPlusAttributeAttribute
Inherits XmlAttributeAttribute
Public Sub New()
MyBase.AttributeName = AttributeName
Me.m_Required = False
End Sub
Private m_Required As Boolean
Public Overridable Property Required() As Boolean
Get
Return m_Required
End Get
Set(value As Boolean)
m_Required = value
End Set
End Property
End Class
我现在可以用它们来装饰我的班级:
<Serializable>
<XmlRoot("INTERFACE")>
Public MustInherit Class WM_Interface
Private m_Message_Type As String
Private m_Event_DTTM As String
Private m_Business_Unit As String
<XMLPlusAttribute(AttributeName:="MESSAGE_TYPE", Required:=True)>
Public Property Message_Type() As String
Get
Return m_Message_Type
End Get
Set(value As String)
m_Message_Type = value
End Set
End Property
<XMLPlusAttribute(AttributeName:="EVENT_DTTM", Required:=True)>
Public Property Event_DTTM() As String
Get
Return m_Event_DTTM
End Get
Set(value As String)
m_Event_DTTM = value
End Set
End Property
<XMLPlusAttribute(AttributeName:="BUSINESS_UNIT", Required:=True)>
Public Property Business_Unit() As String
Get
Return m_Business_Unit
End Get
Set(value As String)
m_Business_Unit = value
End Set
End Property
End Class
<Serializable>
<XmlRoot("INTERFACE")>
Public Class WM_Interface_BOX
Inherits WM_Interface
Private m_Container As WM_Container_BOX
<XMLPlusElement(ElementName:="CONTAINER", IsNullable:=False, Required:=True)>
Public Property Container() As WM_Container_BOX
Get
Return m_Container
End Get
Set(value As WM_Container_BOX)
m_Container = value
End Set
End Property
End Class
<Serializable>
<XmlRoot("INTERFACE")>
Public Class WM_Interface_FIB
Inherits WM_Interface
Private m_Fiber As WM_Fiber
<XMLPlusElement(ElementName:="FIBER", IsNullable:=False, Required:=True)>
Public Property Fiber() As WM_Fiber
Get
Return m_Fiber
End Get
Set(value As WM_Fiber)
m_Fiber = value
End Set
End Property
End Class
所以现在的问题是如何自定义序列化/反序列化过程以利用这个新的“必需”属性。如果我继承 XMLSerializer,我似乎可以覆盖这些方法,但我不确定在其中放什么:
Public Class XMLPlusSerializer
Inherits XmlSerializer
Protected Overrides Function Deserialize(reader As XmlSerializationReader) As Object
Return MyBase.Deserialize(reader)
End Function
Protected Overrides Sub Serialize(o As Object, writer As XmlSerializationWriter)
MyBase.Serialize(o, writer)
End Sub
End Class
我知道我也可以实现 ISerializable 并为每个方法编写自定义的 ReadXML() 和 WriteXML() 方法,但我想要更通用的方法。非常感谢您提出的任何帮助或指导!
【问题讨论】:
-
XmlSerializer实际上并不直接序列化和反序列化。相反,它使用代码生成技术来动态生成执行实际序列化和反序列化的程序集。而且,没有办法继承和覆盖代码生成引擎。另一方面,如果您可以为您的类型制作 XSD,则可以在反序列化时进行验证,如 this answer 所示。 -
正如我所说,XSD 对我不起作用。看看我如何拥有两个都继承自 WM_Interface 的类。两者都有一个名为“INTERFACE”的 XML 元素,但它们内部需要完全不同的元素集才能使它们有效。但是,XSD 不允许您复制
-
那么听起来你有以下选项。 1)实现
IXmlSerializable(您不想这样做)并放入您自己的通用反序列化引擎。 2) 预处理和后处理您的 XML 属性"Message_Type"到"xsi:type"并反序列化为类层次结构。 3) 在OnDeserialized事件中反序列化后手动验证,如How do you find out when you've been loaded via XML Serialization? 所示。 -
谢谢 - 我最终在反序列化后手动验证。为了后代,我发布我自己的答案。
标签: c# vb.net serialization