it-swarm-ko.tech

.NET XML 직렬화 문제가 있습니까?

C # XML 직렬화를 수행 할 때 공유 할 것이라고 생각한 몇 가지 문제에 봉착했습니다.


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{      
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        bool wasEmpty = reader.IsEmptyElement;
        reader.Read();

        if (wasEmpty)
            return;

        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            reader.ReadStartElement("item");

            reader.ReadStartElement("key");
            TKey key = (TKey)keySerializer.Deserialize(reader);
            reader.ReadEndElement();

            reader.ReadStartElement("value");
            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();

            this.Add(key, value);

            reader.ReadEndElement();
            reader.MoveToContent();
        }
        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement("item");

            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

            writer.WriteStartElement("value");
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }
}

다른 XML 직렬화가 있습니까?

120
Kalid

또 다른 큰 문제는 웹 페이지 (ASP.NET)를 통해 XML을 출력 할 때 nicode Byte-Order Mark 를 포함하고 싶지 않은 것입니다. 물론 BOM을 사용하거나 사용하지 않는 방법은 거의 동일합니다.

불량 (BOM 포함) :

XmlTextWriter wr = new XmlTextWriter(stream, new System.Text.Encoding.UTF8);

좋은:

XmlTextWriter  wr = new XmlTextWriter(stream, new System.Text.UTF8Encoding(false))

BOM을 원하지 않음을 나타 내기 위해 명시 적으로 false를 전달할 수 있습니다. Encoding.UTF8UTF8Encoding.

처음에 3 개의 추가 BOM 바이트는 (0xEFBBBF) 또는 (239187191)입니다.

참조 : http://chrislaco.com/blog/troubleshooting-common-problems-with-the-xmlserializer/

27
Kalid

아직 댓글을 달 수 없으므로 Dr8k의 게시물에 댓글을 달고 다시 관찰하겠습니다. 공용 게터/세터 속성으로 노출되고 해당 속성을 통해 직렬화/역 직렬화되는 개인 변수입니다. 우리는 내 오래된 직장에서 항상 그것을했다.

그러나 한 가지 주목할 점은 해당 속성에 로직이 있으면 로직이 실행되므로 직렬화 순서가 실제로 중요하다는 것입니다. 멤버는 코드에서 순서에 따라 암시 적으로로 정렬되지만, 특히 다른 객체를 상속 할 때는 보장 할 수 없습니다. 명백하게 그들을 주문하는 것은 뒤쪽에 고통입니다.

나는 과거에 이것으로 화상을 입었다.

21
Charles Graham

메모리 스트림에서 XML 문자열로 직렬화 할 때는 MemoryStream # GetBuffer () 대신 MemoryStream # ToArray ()를 사용해야합니다.

http://msdn.Microsoft.com/en-us/library/system.io.memorystream.getbuffer (VS.80) .aspx

15
realgt

수익률 반환을 통해 생성 된 IEnumerables<T>는 직렬화 할 수 없습니다. 컴파일러는 수율 반환을 구현하기 위해 별도의 클래스를 생성하고 해당 클래스는 직렬화 가능으로 표시되지 않기 때문입니다.

10
bwillard

시리얼 라이저에 유형의 인터페이스가있는 멤버/프로퍼티가 있으면 직렬화되지 않습니다. 예를 들어, 다음은 XML로 직렬화되지 않습니다.

public class ValuePair
{
    public ICompareable Value1 { get; set; }
    public ICompareable Value2 { get; set; }
}

이것은 직렬화되지만 :

public class ValuePair
{
    public object Value1 { get; set; }
    public object Value2 { get; set; }
}
10
Allon Guralnek

읽기 전용 속성을 직렬화 할 수 없습니다. 역 직렬화를 사용하여 XML을 객체로 변환하지 않더라도 getter 및 setter가 있어야합니다.

같은 이유로 인터페이스를 반환하는 속성을 serialize 할 수 없습니다. deserializer는 인스턴스화 할 구체적인 클래스를 알지 못합니다.

8
Tim Robinson

오 좋은 점이 있습니다. XML 직렬화 코드가 생성되어 별도의 DLL에 배치되므로 코드에 직렬 변환기를 손상시키는 실수가 있어도 의미있는 오류가 발생하지 않습니다. "s3d3fsdf.dll을 (를) 찾을 수 없음"과 같은 것입니다. 좋은.

7
Eric Z Beard

매개 변수가없는 construtor가없는 객체를 직렬화 할 수 없습니다 (그냥 물린 것).

그리고 어떤 이유로 다음 속성에서 Value가 serialize되지만 FullName은 직렬화되지 않습니다.

    public string FullName { get; set; }
    public double Value { get; set; }

나는 왜 그 일을 끝내지 못했는지, 방금 Value를 내부로 변경했습니다 ...

6
Benjol

"기본"XML 직렬화를 사용하는 경우 개인/보호 된 클래스 멤버를 직렬화 할 수 없습니다.

그러나 클래스에서 IXmlSerializable을 구현하는 사용자 정의 XML 직렬화 논리를 지정하고 필요/원하는 개인 필드를 직렬화 할 수 있습니다.

http://msdn.Microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx

5
Max Galkin

Color 및/또는 Font 유형의 개체를 직렬화하는 데 문제가 발생할 수 있습니다.

여기 도움이 된 조언이 있습니다.

http://www.codeproject.com/KB/XML/xmlsettings.aspx

http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx

4
Max Galkin

XML Serializer가 지원하는 내용 및 지원되는 XSD 기능이 지원되는 방법에 대한 자세한 내용은 " 고급 XML 스키마 정의 언어 속성 바인딩 지원 "을 참조하십시오.

4
John Saunders

List<T> 또는 subclassesT의 인스턴스를 포함하는 IEnumerable<T>을 직렬화하려는 경우 다음을 수행해야합니다. 사용되는 모든 하위 유형을 나열하려면 XmlArrayItemAttribute 를 사용하십시오. 그렇지 않으면 직렬화 할 때 런타임에 도움이되지 않는 System.InvalidOperationException이 표시됩니다.

다음은 문서 의 전체 ​​예제 중 일부입니다.

public class Group
{  
   /* The XmlArrayItemAttribute allows the XmlSerializer to insert both the base 
      type (Employee) and derived type (Manager) into serialized arrays. */

   [XmlArrayItem(typeof(Manager)), XmlArrayItem(typeof(Employee))]
   public Employee[] Employees;
4
MarkJ

XML 직렬화로 생성 된 어셈블리가이를 사용하려는 코드와 동일한로드 컨텍스트에없는 경우 다음과 같은 멋진 오류가 발생합니다.

System.InvalidOperationException: There was an error generating the XML document.
---System.InvalidCastException: Unable to cast object
of type 'MyNamespace.Settings' to type 'MyNamespace.Settings'. at
Microsoft.Xml.Serialization.GeneratedAssembly.
  XmlSerializationWriterSettings.Write3_Settings(Object o)

이 문제의 원인은 LoadFrom context 를 사용하여로드 된 플러그인이므로 Load 컨텍스트를 사용하는 데 많은 단점이 있습니다. 그 중 하나를 추적하는 것은 꽤 재미있는 일입니다.

4
user7116

Obsolete 특성으로 표시된 속성은 직렬화되지 않습니다. Deprecated 속성으로 테스트하지는 않았지만 같은 방식으로 작동한다고 가정합니다.

3
James Hulse

개인 변수/속성은 XML 직렬화의 기본 메커니즘에서 직렬화되지 않지만 2 진 직렬화입니다.

3
Charles Graham

XSD가 대체 그룹을 사용하는 경우 자동으로 직렬화를 해제 할 수 없습니다. 이 시나리오를 처리하려면 고유 한 직렬 변환기를 작성해야합니다.

예 :.

<xs:complexType name="MessageType" abstract="true">
    <xs:attributeGroup ref="commonMessageAttributes"/>
</xs:complexType>

<xs:element name="Message" type="MessageType"/>

<xs:element name="Envelope">
    <xs:complexType mixed="false">
        <xs:complexContent mixed="false">
            <xs:element ref="Message" minOccurs="0" maxOccurs="unbounded"/>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

<xs:element name="ExampleMessageA" substitutionGroup="Message">
    <xs:complexType mixed="false">
        <xs:complexContent mixed="false">
                <xs:attribute name="messageCode"/>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

<xs:element name="ExampleMessageB" substitutionGroup="Message">
    <xs:complexType mixed="false">
        <xs:complexContent mixed="false">
                <xs:attribute name="messageCode"/>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

이 예에서 봉투에는 메시지가 포함될 수 있습니다. 그러나 .NET의 기본 직렬 변환기는 Message, ExampleMessageA 및 ExampleMessageB를 구분하지 않습니다. 기본 Message 클래스와 만 직렬화됩니다.

2
ilitirit

명시적인 직렬화없이 형식을 신중하게 직렬화하면 .Net이 빌드하는 동안 지연 될 수 있습니다. 최근에 이것을 발견했습니다 RSAParameters를 직렬화하는 동안 .

2
Keith

나는 이것을 정말로 설명 할 수는 없지만 이것이 직렬화되지는 않는다는 것을 알았다.

[XmlElement("item")]
public myClass[] item
{
    get { return this.privateList.ToArray(); }
}

그러나 이것은 :

[XmlElement("item")]
public List<myClass> item
{
    get { return this.privateList; }
}

또한 memstream으로 직렬화하는 경우 사용하기 전에 0을 찾고 싶을 수도 있습니다.

2
annakata

개인 변수/속성은 XML 직렬화로 직렬화되지 않지만 이진 직렬화로되어 있습니다.

공개 속성을 통해 비공개 멤버를 노출하는 경우 에도이 정보가 표시됩니다. 비공개 멤버는 직렬화되지 않으므로 공개 멤버가 모두 null 값을 참조합니다.

0
Dr8k