假设我在 Visual Studio 中有两个项目。基础项目和派生项目。
基础项目包含一个基类:
Public Class Car
Property Name As String
End Class
以及用于序列化的通用类
Public Class Seriallizer(Of T)
Function SerializeObjToString(obj As T) As String
Dim serializer As XmlSerializer
Dim memStream As New MemoryStream
Dim xmlWriter As New XmlTextWriter(memStream, Encoding.UTF8)
Try
serializer = New XmlSerializer(GetType(T))
serializer.Serialize(xmlWriter, obj)
Dim xml As String
xml = Encoding.UTF8.GetString(memStream.GetBuffer)
xml = xml.Substring(xml.IndexOf(Convert.ToChar(60)))
xml = xml.Substring(0, (xml.LastIndexOf(Convert.ToChar(62)) + 1))
Return xml
Catch e As Exception
MsgBox($"Error writing data to string: {e.Message}")
Finally
xmlWriter.Close()
memStream.Close()
xmlWriter = Nothing
serializer = Nothing
memStream = Nothing
End Try
Return ""
End Function
现在我在我的第二个项目中派生了类“SpecialCar”。
Public Class SpecialCar
Inherits Car
Sub New()
MyBase.New
End Sub
Property VentorName As String
End Class
我的带有派生类的项目引用了基类项目。 当我现在想要序列化派生类时,我收到错误:
Dim spezicalCar As New SpecialCar
Dim serializer As New Seriallizer(Of Car)
Dim str As String = serializer.SerializeObjToString(spezicalCar)
错误:
The type Derived.SpecialCar was not expected.
Use the XmlInclude or SoapInclude attribute to specify types that are not
known statically
我知道,我可以使用 XMLInclude 属性,但这在这种情况下不起作用,因为基类项目不知道派生类项目。在其他 SO 帖子中,我读到了一些有关为类提供 xml 命名空间的内容,但我不知道该怎么做。 如何将派生类序列化为 XML?
经过一天的研究,我找到了我的问题的解决方案。
首先,您需要编写自己的序列化器类(应该是通用的,您可以将它用于所有抽象(Base/MustInherit)类)。 以下 SO 和 codeproject.com 链接帮助我解决了任务:
https://www.codeproject.com/Articles/8644/XmlSerializer-and-not-expected-Inherited-Types
在这两个链接中,您将找到类似的解决方案。请注意,在代码项目链接中,您必须在评论部分中查找通用解决方案。
这是我最终的通用序列化器类,您可以将其放置在带有基类的项目中,或者放置在专用项目中,并将基类中的引用添加到专用项目中。
Imports System.Xml
Imports System.Xml.Schema
Imports System.Xml.Serialization
Public Class GenericSerializer(Of T)
Implements IXmlSerializable
Public Shared Widening Operator CType(p As GenericSerializer(Of T)) As T
Return IIf(p Is Nothing, Nothing, p.Derived)
End Operator
Public Shared Widening Operator CType(p As T) As GenericSerializer(Of T)
Return IIf(p Is Nothing, Nothing, New GenericSerializer(Of T)(p))
End Operator
Private _derived As T
Public ReadOnly Property Derived As T
Get
Return _derived
End Get
End Property
Public Sub New()
'Nothing to do here
End Sub
Public Sub New(ByVal derived As T)
Me._derived = derived
End Sub
Public Sub ReadXml(reader As XmlReader) Implements IXmlSerializable.ReadXml
Dim typeAttrib As String = reader.GetAttribute("type")
' Ensure the Type was Specified
If (typeAttrib Is Nothing) Then
Throw New ArgumentNullException(("Unable to Read Xml Data for Abstract Type '" _
+ (GetType(T).Name + "' because no 'type' attribute was specified in the XML.")))
End If
Dim type As Type = Type.GetType(typeAttrib)
' Check the Type is Found.
If (type Is Nothing) Then
Throw New InvalidCastException(("Unable to Read Xml Data for Abstract Type '" _
+ (GetType(T).Name + "' because the type specified in the XML was not found.")))
End If
If Not type.IsSubclassOf(GetType(T)) Then
Throw New InvalidCastException(("Unable to Read Xml Data for Abstract Type '" _
+ (GetType(T).Name + ("' because the Type specified in the XML differs ('" _
+ (type.Name + "').")))))
End If
reader.ReadStartElement()
Me._derived = New XmlSerializer(type).Deserialize(reader)
reader.ReadEndElement()
End Sub
Public Sub WriteXml(writer As XmlWriter) Implements IXmlSerializable.WriteXml
Dim type As Type = Me._derived.GetType
writer.WriteAttributeString("type", type.AssemblyQualifiedName.ToString)
Call New XmlSerializer(_derived.GetType).Serialize(writer, _derived)
End Sub
Public Function GetSchema() As XmlSchema Implements IXmlSerializable.GetSchema
Return Nothing
End Function
End Class
不幸的是,我必须将基类包装在另一个类中才能使用自定义序列化器。
Imports System.Xml.Serialization
Public Class Car
Property Name As String
End Class
Public Class XMLCar
<XmlElement(GetType(GenericSerializer(Of Car)), ElementName:="Car")>
Property Car As Car
End Class
像这样调用序列化器:
Dim spezicalCar As New SpecialCar
Dim serializer As New Seriallizer
Dim xmlCar As New XMLCar With {.Car = spezicalCar}
Dim str As String = serializer.SerializeObjToString(Of XMLCar)(xmlCar)
您还可以在派生类对象列表上使用它:
<XmlArrayItem(GetType(GenericSerializer(Of Car)))>
Property CarList As List(Of Car)