2010-04-19 4 views
4

Я пытался создать общий Dictionary, который реализует IXmlSerializable (кредит Charles Feduke).IXmlSerializable Dictionary problem

Вот моя проба:

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 и я вижу, что, когда он останавливается, автор не содержит никаких данных на всех , и IMHO он должен содержать корневой элемент и объявление 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 

ответ

1

Почему он содержит корень? Вы не добавляете один в Serialize, на котором создается XmlWriter ... Интересно, если вы должны иметь что-то более, как (C#, извините):

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, чтобы включить внешний элемент по вашему выбору.

+0

Мне также нужна помощь с помощью метода Parse, потому что Deserialize возвращает новый объект, я хочу «воссоздать» текущий экземпляр, используя свой собственный ReadXml. – Shimmy

+0

@Shimmy - и где это сейчас разрушается? В чем проблема/проблема? –

+0

Нет, первая проблема была решена с помощью вашего фрагмента, другая проблема заключается в том, что я хочу иметь функцию Parse, которая очищает текущую коллекцию и загружает элементы из строкового представления сериализованного экземпляра. – Shimmy

1

Не ответ, но я нашел 2 ошибки в коде шимми в (спасибо, кстати) и один Гоча для тех, кто пытается использовать это против .Net 2.0

В ошибки связаны друг с другом. Призывы:

WriteData(IsKeyAttributable, writer, True, entry.Key) 
WriteData(IsValueAttributable, writer, False, entry.Value) 

должен быть

WriteData(IsKeyAttributable, writer, True, DirectCast(entry.Key, TKey)) 
WriteData(IsValueAttributable AndAlso IsKeyAttributable, writer, False, CType(entry.Value, TValue)) 

Если то есть ключ не может быть атрибутом XML, то значение не может быть атрибутом XML. Кроме того, необходимо указать запись. Ключ и запись. Добавьте его в TKey/TValue, иначе XMLSerializer жалуется позже. Также

Аналогично вызов

Dim value = ReadData(Of TValue)(IsValueAttributable, reader, False) 

должен быть

Dim value = ReadData(Of TValue)(IsValueAttributable AndAlso IsKeyAttributable, reader, False) 

т.е. Агинский проверить, что ключ attributale если значение связано

И для тех, кто ориентируетесь среды исполнения .NET 2.0 вам понадобится предикат GetIsAttributable, объявленный как

Private Shared ReadOnly GetIsAttributable As Predicate(Of Type) = Function(t) DirectCast(AttributableTypes, IList).Contains(t) 

 Смежные вопросы

  • Нет связанных вопросов^_^