2010-04-19 2 views
4

IXmlSerializable (신용 : Charles Feduke)을 구현하는 일반 Dictionary을 만들려고했습니다. 여기 IXmlSerializable 사전 문제

내 재판입니다 :

Sub Main() 
    Dim z As New SerializableDictionary(Of String, String) 
    z.Add("asdf", "asd") 
    Console.WriteLine(z.Serialize) 
End Sub 

결과 : I가되는 WriteXml 방법의 상단에 중단 점을 배치하고 난 멈출 때, 작가는 모든 데이터가없는 것을 볼

<?xml version="1.0" encoding="utf-16"?><Entry key="asdf" value="asd" /> 

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

는 왜 루트를 포함 할 것인가? 당신이 더 많은 뭔가를해야한다면 당신은 당신이 XmlWriter을 만들 Serialize에 하나를 추가하지 않는 ... 궁금 (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

Deserialize가 새 개체를 반환하기 때문에 Parse 메서드도 도움이 필요합니다. 자체 ReadXml을 사용하여 현재 인스턴스를 다시 만들고 싶습니다. – Shimmy

+0

@Shimmy - 현재 그 곳은 현재 고장입니까? 거기에있는 질문/문제는 무엇입니까? –

+0

아니요. 첫 번째 문제가 스 니펫으로 해결되었지만 다른 문제는 현재 컬렉션을 지우고 직렬화 된 인스턴스의 문자열 표현에서 항목을로드하는 Parse 함수가 필요합니다. – Shimmy

1

하지 대답,하지만 난 (그런데 감사) 및 .NET 2.0

벌레가 서로 관련에 대해이 사용하려는 사람들을 위해 하나 개 잡았다 이상 진동의 코드에서이 버그를 발견했다. 호출은에 :

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

는 키가 XML 속성이 될 수없는 경우

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

은 즉, 값이 XML 속성이 될 수 있어야한다. 또한 항목을 캐스팅해야합니다 .Key 및 entry.Value는 TKey/TValue입니다. 그렇지 않으면 XMLSerializer가 나중에 불만을 제기합니다. 또한

마찬가지로 호출

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

같아야

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

즉 Agin 값이 발생한 경우 키 attributale인지 확인

및 .NET 런타임 2.0 표적으로에게는

로 선언 된 GetIsAttributable 선언문이 필요합니다.
Private Shared ReadOnly GetIsAttributable As Predicate(Of Type) = Function(t) DirectCast(AttributableTypes, IList).Contains(t) 
관련 문제