.NET XML 직렬화 문제? [닫은]


121

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 직렬화 문제가 있습니까?


더 많은 gotchas 롤을 찾고, 당신은 나를 도울 수 있을지도 모릅니다 : stackoverflow.com/questions/2663836/…
Shimmy Weitzhandler

1
또한 Charles Feduke의 직렬화 가능한 사전 구현을 살펴보고 싶을 것입니다. 그는 기본 직렬화 프로그램에 의해 직렬화 될 정규 구성원에 대한 귀속 가능한 구성원 사이에 xml 작성자를 알릴 수 있도록했습니다. deploymentzone.com/2008/09/19/…
Shimmy Weitzhandler

이것은 모든 문제를 해결하는 것 같지 않습니다. 생성자에서 IEqualityComparer를 설정하고 있지만이 코드에서는 직렬화되지 않습니다. 이 정보를 포함하도록이 사전을 확장하는 방법에 대한 아이디어가 있습니까? 그 정보는 Type 객체를 통해 처리 될 수 있습니까?
ColinCren

답변:


27

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

BAD (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/


4
당신의 의견은 당신이 우리에게 무엇을뿐만 아니라 이유를 말하면 훨씬 더 유용 할 것입니다.
Neil

1
이것은 정말 ... XML 직렬화에 관한 그것은 단지 XmlTextWriter의 문제입니다하지 않습니다
토마스 레베을

7
-1 : 질문과 관련이 없으며 XmlTextWriter.NET 2.0 이상에서 사용해서는 안됩니다 .
John Saunders

매우 유용한 참조 링크. 감사.
Anil Vangari 2012-06-21

21

아직 댓글을 달 수 없어서 Dr8k의 게시물에 댓글을 달고 또 다른 관찰을하겠습니다. 공용 getter / setter 속성으로 노출되고 이러한 속성을 통해 직렬화 / 역 직렬화되는 개인 변수. 우리는 항상 예전 직장에서 해냈습니다.

하지만 한 가지 주목할 점은 해당 속성에 논리가있는 경우 논리가 실행되기 때문에 직렬화 순서가 실제로 중요하다는 것입니다. 멤버는 코드에서 정렬 된 방식에 따라 암시 적으로 정렬되지만 특히 다른 개체를 상속하는 경우에는 보장되지 않습니다. 명시 적으로 주문하는 것은 후방의 고통입니다.

나는 과거에 이것에 타 버린 적이 있습니다.


17
필드 순서를 명시 적으로 설정하는 방법을 검색하는 동안이 게시물을 찾았습니다. 이것은 속성으로 수행됩니다. [XmlElementAttribute (Order = 1)] public int Field {...} 단점 : 속성은 클래스의 모든 필드와 모든 하위 항목에 대해 지정되어야합니다! IMO 당신은 이것을 당신의 포스트에 추가해야합니다.
Cristian Diaconescu

15

메모리 스트림에서 XML 문자열로 직렬화 할 때 MemoryStream # GetBuffer () 대신 MemoryStream # ToArray ()를 사용해야합니다. 그렇지 않으면 할당 된 추가 버퍼로 인해 제대로 역 직렬화되지 않는 정크 문자로 끝납니다.

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


3
문서에서 바로 "버퍼에는 사용되지 않을 수있는 할당 된 바이트가 포함되어 있습니다. 예를 들어"test "문자열이 MemoryStream 객체에 기록되면 GetBuffer에서 반환 된 버퍼의 길이는 252 바이트로 4가 아니라 256입니다. 사용되지 않습니다. 버퍼의 데이터 만 얻으려면 ToArray 메서드를 사용하십시오. 그러나 ToArray는 메모리에 데이터 복사본을 만듭니다. " msdn.microsoft.com/en-us/library/…
realgt

방금 이걸 봤어요. 더 이상 말도 안되는 소리가 아닙니다.
John Saunders

이것은 디버깅에 도움이되는 이전에 들어 본 적이 없습니다.
Ricky

10

serializer가 유형으로 인터페이스가있는 멤버 / 속성을 발견하면 직렬화되지 않습니다. 예를 들어 다음은 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; }
}

"구성원에 대해 유형이 확인되지 않았습니다 ..."라는 메시지와 함께 예외가 발생하면이 문제가 발생할 수 있습니다.
Kyle Krull

9

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


이것은 '기타'직렬화, 즉 [Serializable] 속성에 적용됩니다. 그러나 XmlSerializer에서도 작동하지 않습니다.
Tim Robinson


8

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

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


1
실제로 컬렉션 속성은 setter가 없어도 직렬화 할 수 있지만 생성자에서 초기화해야 deserialization이 항목을 추가 할 수 있습니다
Thomas Levesque

7

오 여기 좋은 것이 있습니다. XML 직렬화 코드가 생성되어 별도의 DLL에 배치되기 때문에 코드에 직렬화를 중단시키는 실수가 있어도 의미있는 오류가 발생하지 않습니다. "s3d3fsdf.dll을 찾을 수 없음"과 같은 것입니다. 좋은.


11
XML "Serializer Generator Tool (Sgen.exe)"를 사용하여 해당 DLL을 미리 생성하고 응용 프로그램과 함께 배포 할 수 있습니다.
huseyint

6

매개 변수없는 생성자가없는 객체는 직렬화 할 수 없습니다.

그리고 어떤 이유로 다음 속성에서 Value는 직렬화되지만 FullName은 아닙니다.

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

왜 그런지 알아 내지 못했지만 Value를 내부로 변경했습니다 ...


4
매개 변수없는 생성자는 개인 / 보호 될 수 있습니다. XML serializer에 충분합니다. FullName의 문제는 정말 이상합니다. 발생해서는 안됩니다.
Max Galkin 2009-06-17

@Yacoder : 어쩌면 때문에하지 double?하지만 단지 double?
abatishchev 2011 년

FullName은 아마도 null직렬화 될 때 XML을 생성하지 않을 것입니다
Jesper


4

XML Serialization 생성 어셈블리가이를 사용하려는 코드와 동일한로드 컨텍스트에 있지 않으면 다음과 같은 멋진 오류가 발생합니다.

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 컨텍스트 를 사용하여로드 된 플러그인이었습니다 . 그것을 추적하는 것은 꽤 재미 있습니다.




4

당신이 배열 직렬화하려고하면 List<T>, 또는 IEnumerable<T>인스턴스가 들어 서브 클래스 의를 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;

3

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


2
예, "기본"XML 직렬화를 사용하는 경우입니다. 클래스에서 IXmlSerializable을 구현하는 사용자 지정 XML 직렬화 논리를 지정하고 필요 / 원하는 모든 개인 필드를 직렬화 할 수 있습니다.
Max Galkin

1
음, 사실입니다. 나는 이것을 편집 할 것이다. 그러나 그 인터페이스를 구현하는 것은 내가 기억하는 것에서 일종의 고통입니다.
Charles Graham

3

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


2

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

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

그러나 이것은 :

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

또한 memstream으로 직렬화하는 경우 사용하기 전에 0을 찾는 것이 좋습니다.


재건 할 수 없기 때문이라고 생각합니다. 두 번째 예제에서는 item.Add ()를 호출하여 항목을 목록에 추가 할 수 있습니다. 처음에는 할 수 없습니다.
ilitirit

18
사용 : [XmlArray ( "item"), XmlArrayItem ( "myClass", typeof (myClass))]
RvdK

1
건배! 매일 무언가를 배우십시오
annakata


2

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의 기본 serializer는 Message, ExampleMessageA 및 ExampleMessageB를 구분하지 않습니다. 기본 Message 클래스로만 직렬화됩니다.


0

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

공개 속성을 통해 비공개 멤버를 노출하는 경우에도 이것이 얻을 수 있다고 생각합니다. 비공개 멤버는 직렬화되지 않으므로 공개 멤버는 모두 null 값을 참조합니다.


이것은 사실이 아닙니다. public 속성의 setter가 호출되고 아마도 private 멤버를 설정합니다.
John Saunders
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.