IXmlSerialized 字典问题
我试图创建一个实现 IXmlSerialized
的通用 Dictionary
(归功于 查尔斯·费杜克)。
这是我的试验:
Sub Main()
Dim z As New SerializableDictionary(Of String, String)
z.Add("asdf", "asd")
Console.WriteLine(z.Serialize)
End Sub
结果:
<?xml version="1.0" encoding="utf-16"?><Entry key="asdf" value="asd" />
我在 WriteXml 方法顶部放置了一个断点,我发现当它停止时,编写器根本不包含任何数据,恕我直言,它应该包含根元素和 xml 声明。
<Serializable()> _
Public Class SerializableDictionary(Of TKey, TValue) : Inherits Dictionary(Of TKey, TValue) : Implements IXmlSerializable
Private Const EntryString As String = "Entry"
Private Const KeyString As String = "key"
Private Const ValueString As String = "value"
Private Shared ReadOnly AttributableTypes As Type() = New Type() {GetType(Boolean), GetType(Byte), GetType(Char), GetType(DateTime), GetType(Decimal), GetType(Double), GetType([Enum]), GetType(Guid), GetType(Int16), GetType(Int32), GetType(Int64), GetType(SByte), GetType(Single), GetType(String), GetType(TimeSpan), GetType(UInt16), GetType(UInt32), GetType(UInt64)}
Private Shared ReadOnly GetIsAttributable As Predicate(Of Type) = Function(t) AttributableTypes.Contains(t)
Private Shared ReadOnly IsKeyAttributable As Boolean = GetIsAttributable(GetType(TKey))
Private Shared ReadOnly IsValueAttributable As Boolean = GetIsAttributable(GetType(TValue))
Private Shared ReadOnly GetElementName As Func(Of Boolean, String) = Function(isKey) If(isKey, KeyString, ValueString)
Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
Return Nothing
End Function
Public Sub WriteXml(ByVal writer As XmlWriter) Implements IXmlSerializable.WriteXml
For Each entry In Me
writer.WriteStartElement(EntryString)
WriteData(IsKeyAttributable, writer, True, entry.Key)
WriteData(IsValueAttributable, writer, False, entry.Value)
writer.WriteEndElement()
Next
End Sub
Private Sub WriteData(Of T)(ByVal attributable As Boolean, ByVal writer As XmlWriter, ByVal isKey As Boolean, ByVal value As T)
Dim name = GetElementName(isKey)
If attributable Then
writer.WriteAttributeString(name, value.ToString)
Else
Dim serializer As New XmlSerializer(GetType(T))
writer.WriteStartElement(name)
serializer.Serialize(writer, value)
writer.WriteEndElement()
End If
End Sub
Public Sub ReadXml(ByVal reader As XmlReader) Implements IXmlSerializable.ReadXml
Dim empty = reader.IsEmptyElement
reader.Read()
If empty Then Exit Sub
Clear()
While reader.NodeType <> XmlNodeType.EndElement
While reader.NodeType = XmlNodeType.Whitespace
reader.Read()
Dim key = ReadData(Of TKey)(IsKeyAttributable, reader, True)
Dim value = ReadData(Of TValue)(IsValueAttributable, reader, False)
Add(key, value)
If Not IsKeyAttributable AndAlso Not IsValueAttributable Then reader.ReadEndElement() Else reader.Read()
While reader.NodeType = XmlNodeType.Whitespace
reader.Read()
End While
End While
reader.ReadEndElement()
End While
End Sub
Private Function ReadData(Of T)(ByVal attributable As Boolean, ByVal reader As XmlReader, ByVal isKey As Boolean) As T
Dim name = GetElementName(isKey)
Dim type = GetType(T)
If attributable Then
Return Convert.ChangeType(reader.GetAttribute(name), type)
Else
Dim serializer As New XmlSerializer(type)
While reader.Name <> name
reader.Read()
End While
reader.ReadStartElement(name)
Dim value = serializer.Deserialize(reader)
reader.ReadEndElement()
Return value
End If
End Function
Public Shared Function Serialize(ByVal dictionary As SerializableDictionary(Of TKey, TValue)) As String
Dim sb As New StringBuilder(1024)
Dim sw As New StringWriter(sb)
Dim xs As New XmlSerializer(GetType(SerializableDictionary(Of TKey, TValue)))
xs.Serialize(sw, dictionary)
sw.Dispose()
Return sb.ToString
End Function
Public Shared Function Deserialize(ByVal xml As String) As SerializableDictionary(Of TKey, TValue)
Dim xs As New XmlSerializer(GetType(SerializableDictionary(Of TKey, TValue)))
Dim xr As New XmlTextReader(xml, XmlNodeType.Document, Nothing)
xr.Close()
Return xs.Deserialize(xr)
End Function
Public Function Serialize() As String
Dim sb As New StringBuilder
Dim xw = XmlWriter.Create(sb)
WriteXml(xw)
xw.Close()
Return sb.ToString
End Function
Public Sub Parse(ByVal xml As String)
Dim xr As New XmlTextReader(xml, XmlNodeType.Document, Nothing)
ReadXml(xr)
xr.Close()
End Sub
End Class
I was trying to create a generic Dictionary
that implements IXmlSerializable
(credit to Charles Feduke).
Here is my trial:
Sub Main()
Dim z As New SerializableDictionary(Of String, String)
z.Add("asdf", "asd")
Console.WriteLine(z.Serialize)
End Sub
Result:
<?xml version="1.0" encoding="utf-16"?><Entry key="asdf" value="asd" />
I placed a breakpoint on top of the WriteXml method and I see that when it stops, the writer contains no data at all, and IMHO it should contain the root element and the xml declaration.
<Serializable()> _
Public Class SerializableDictionary(Of TKey, TValue) : Inherits Dictionary(Of TKey, TValue) : Implements IXmlSerializable
Private Const EntryString As String = "Entry"
Private Const KeyString As String = "key"
Private Const ValueString As String = "value"
Private Shared ReadOnly AttributableTypes As Type() = New Type() {GetType(Boolean), GetType(Byte), GetType(Char), GetType(DateTime), GetType(Decimal), GetType(Double), GetType([Enum]), GetType(Guid), GetType(Int16), GetType(Int32), GetType(Int64), GetType(SByte), GetType(Single), GetType(String), GetType(TimeSpan), GetType(UInt16), GetType(UInt32), GetType(UInt64)}
Private Shared ReadOnly GetIsAttributable As Predicate(Of Type) = Function(t) AttributableTypes.Contains(t)
Private Shared ReadOnly IsKeyAttributable As Boolean = GetIsAttributable(GetType(TKey))
Private Shared ReadOnly IsValueAttributable As Boolean = GetIsAttributable(GetType(TValue))
Private Shared ReadOnly GetElementName As Func(Of Boolean, String) = Function(isKey) If(isKey, KeyString, ValueString)
Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
Return Nothing
End Function
Public Sub WriteXml(ByVal writer As XmlWriter) Implements IXmlSerializable.WriteXml
For Each entry In Me
writer.WriteStartElement(EntryString)
WriteData(IsKeyAttributable, writer, True, entry.Key)
WriteData(IsValueAttributable, writer, False, entry.Value)
writer.WriteEndElement()
Next
End Sub
Private Sub WriteData(Of T)(ByVal attributable As Boolean, ByVal writer As XmlWriter, ByVal isKey As Boolean, ByVal value As T)
Dim name = GetElementName(isKey)
If attributable Then
writer.WriteAttributeString(name, value.ToString)
Else
Dim serializer As New XmlSerializer(GetType(T))
writer.WriteStartElement(name)
serializer.Serialize(writer, value)
writer.WriteEndElement()
End If
End Sub
Public Sub ReadXml(ByVal reader As XmlReader) Implements IXmlSerializable.ReadXml
Dim empty = reader.IsEmptyElement
reader.Read()
If empty Then Exit Sub
Clear()
While reader.NodeType <> XmlNodeType.EndElement
While reader.NodeType = XmlNodeType.Whitespace
reader.Read()
Dim key = ReadData(Of TKey)(IsKeyAttributable, reader, True)
Dim value = ReadData(Of TValue)(IsValueAttributable, reader, False)
Add(key, value)
If Not IsKeyAttributable AndAlso Not IsValueAttributable Then reader.ReadEndElement() Else reader.Read()
While reader.NodeType = XmlNodeType.Whitespace
reader.Read()
End While
End While
reader.ReadEndElement()
End While
End Sub
Private Function ReadData(Of T)(ByVal attributable As Boolean, ByVal reader As XmlReader, ByVal isKey As Boolean) As T
Dim name = GetElementName(isKey)
Dim type = GetType(T)
If attributable Then
Return Convert.ChangeType(reader.GetAttribute(name), type)
Else
Dim serializer As New XmlSerializer(type)
While reader.Name <> name
reader.Read()
End While
reader.ReadStartElement(name)
Dim value = serializer.Deserialize(reader)
reader.ReadEndElement()
Return value
End If
End Function
Public Shared Function Serialize(ByVal dictionary As SerializableDictionary(Of TKey, TValue)) As String
Dim sb As New StringBuilder(1024)
Dim sw As New StringWriter(sb)
Dim xs As New XmlSerializer(GetType(SerializableDictionary(Of TKey, TValue)))
xs.Serialize(sw, dictionary)
sw.Dispose()
Return sb.ToString
End Function
Public Shared Function Deserialize(ByVal xml As String) As SerializableDictionary(Of TKey, TValue)
Dim xs As New XmlSerializer(GetType(SerializableDictionary(Of TKey, TValue)))
Dim xr As New XmlTextReader(xml, XmlNodeType.Document, Nothing)
xr.Close()
Return xs.Deserialize(xr)
End Function
Public Function Serialize() As String
Dim sb As New StringBuilder
Dim xw = XmlWriter.Create(sb)
WriteXml(xw)
xw.Close()
Return sb.ToString
End Function
Public Sub Parse(ByVal xml As String)
Dim xr As New XmlTextReader(xml, XmlNodeType.Document, Nothing)
ReadXml(xr)
xr.Close()
End Sub
End Class
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为什么它会包含一个根?您没有在创建
XmlWriter
的Serialize
中添加一个...我想知道您是否应该有更像的东西(C#,抱歉):这使用常规
XmlSerializer
核心,用于编写外部元素之类的事情。或者,更改Serialize
以包含您选择的外部元素。Why would it contain a root? You aren't adding one in
Serialize
, where you create theXmlWriter
... I wonder if you should have something more like (C#, sorry):This uses the regular
XmlSerializer
core for things like writing the outer element(s). Alternatively, changeSerialize
to include an outer element of your choosing.不是答案,但我在 Shimmy 的代码中发现了 2 个错误(顺便感谢),并且对于那些试图针对 .Net 2.0 使用此代码的人来说,有一个问题。
这些错误彼此相关。调用:
应该是
ie 如果键不能是 XML 属性,则值不能是 XML 属性。另外,需要将entry.Key和entry.Value转换为TKey/TValue,否则XMLSerializer稍后会抱怨。
同样
,调用
应该是,
即如果值是可归因的,则再次检查键是否是可归因的
对于那些针对 .Net 运行时 2.0 的目标,您将需要将 GetIsAttributable 谓词声明为
Not an answer, but I found 2 bugs in Shimmy's code (thanks by the way) and one gotcha for those trying to use this against .Net 2.0
The bugs are related to each other. The calls to:
should be
i.e If the Key is not able to be an XML attribute, then the value cannot be an XML attribute. Also, need to cast the entry.Key and entry.Value to it's TKey/TValue, otherwise the XMLSerializer complains later on.
Also
Similarly the call
should be
i.e Agin check that the key is attributale if the value is attributable
And for those targetting .Net runtime 2.0 you will need the GetIsAttributable predicate declared as