首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IXmlSerializable字典问题

IXmlSerializable字典问题
EN

Stack Overflow用户
提问于 2010-04-19 03:23:21
回答 2查看 1.5K关注 0票数 4

我试图创建一个通用的Dictionary来实现IXmlSerializable (归功于查尔斯·费克)。

这是我的审判:

代码语言:javascript
复制
Sub Main()
    Dim z As New SerializableDictionary(Of String, String)
    z.Add("asdf", "asd")
    Console.WriteLine(z.Serialize)
End Sub

结果:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-16"?><Entry key="asdf" value="asd" />

我在WriteXml方法的顶部放置了一个断点,当它停止时,作者根本不包含任何数据,IMHO应该包含根元素和xml声明。

代码语言:javascript
复制
<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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-04-19 04:04:49

它为什么要包含一个根?您不是在Serialize中添加一个,而是在其中创建XmlWriter.我想知道你是否应该有更像(C#,对不起)的东西:

代码语言:javascript
复制
public string Serialize() {
    StringBuilder sb = new StringBuilder();
    XmlSerializer ser = new XmlSerializer(
        typeof(SerializableDictionary<TKey, TValue>));
    using (XmlWriter writer = XmlWriter.Create(sb)) {
        ser.Serialize(writer, this);
    }
    return sb.ToString();
}

这将使用常规的XmlSerializer核心来编写外部元素。或者,将Serialize更改为包含您选择的外部元素。

票数 1
EN

Stack Overflow用户

发布于 2010-06-04 06:33:00

不是一个答案,但我在Shimmy的代码中发现了两个bug(顺便说一句),其中一个错误是那些试图将它用于.Net 2.0的人。

这些虫子是互相关联的。呼吁:

代码语言:javascript
复制
WriteData(IsKeyAttributable, writer, True, entry.Key)
WriteData(IsValueAttributable, writer, False, entry.Value)

应该是

代码语言:javascript
复制
WriteData(IsKeyAttributable, writer, True, DirectCast(entry.Key, TKey))
WriteData(IsValueAttributable  AndAlso IsKeyAttributable, writer, False, CType(entry.Value, TValue))

也就是说,如果键不能是XML属性,那么该值就不能是XML属性。另外,需要将entry.Key和entry.Value转换为TKey/TValue,否则XMLSerializer稍后会发出抱怨。也是

类似地,呼叫

代码语言:javascript
复制
Dim value = ReadData(Of TValue)(IsValueAttributable, reader, False)

应该是

代码语言:javascript
复制
Dim value = ReadData(Of TValue)(IsValueAttributable AndAlso IsKeyAttributable, reader, False)

如果该值是可归因的,则检查键是否为属性。

对于那些获得.Net运行时2.0的用户,您需要声明为

代码语言:javascript
复制
Private Shared ReadOnly GetIsAttributable As Predicate(Of Type) = Function(t) DirectCast(AttributableTypes, IList).Contains(t)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2665041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档