2011-09-20 4 views
7

XML에 List<>이 포함 된 클래스를 serialize하려는 C# .NET 3.5 응용 프로그램이 있습니다.List <> XML에 ICollection <>으로 내 보낸

Bar b1 = new Bar(); 
// populate b1 with interesting data 
Bar b2 = new Bar(); 
// populate b2 with interesting data 

Foo f = new Foo(); 
f.Bars.Add(b1); 
f.Bars.Add(b2); 

을 그리고 다음과 같이 직렬화 : :이처럼 그것을 채울 경우

[XmlRoot("Foo")] 
class Foo 
{ 
    private List<Bar> bar_ = new List<Bar>(); 

    private string something_ = "My String"; 

    [XmlElement("Something")] 
    public string Something { get { return something_; } } 

    [XmlElement("Bar")] 
    public ICollection<Bar> Bars 
    { 
     get { return bar_; } 
    } 
} 

: 내 클래스는 다음과 같습니다

using (System.IO.TextWriter textWriter = new System.IO.StreamWriter(@"C:\foo.xml")) 
{ 
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Foo)); 
    serializer.Serialize(textWriter, f); 
} 

나는이처럼 보이는 파일을 가져 :

<Foo> 
    <Something>My String</Something> 
</Foo> 

하지만 원하는 것은 X입니다. 다음과 같습니다 ML :

나는 List<>가 XML에 표시하려면 어떻게해야합니까 무엇
<Foo> 
    <Something>My String</Something> 
    <Bar> 
     <!-- Data from first Bar --> 
    </Bar> 
    <Bar> 
     <!-- Data from second Bar --> 
    </Bar> 
</Foo> 

?

+0

인터페이스를 'XmlSerialize'할 수 있다고 생각하지 않습니다. 어쨌든'ICollection'으로 직렬화하고 싶은 이유는 무엇입니까? 'List '으로 직렬화하고 소비자에게'ICollection '... ??? – IAbstract

+0

@IAbstract - 이해할 수 있는지 잘 모르겠습니다. '[XmlElement ("Bar")]'태그를 사용하여'private list bar_'을 표시하겠습니까? 그것은 출력을 변경하지 않습니다. 또한,'XmlSerializer' 문서는'IEnumerable'과'ICollection' 인터페이스 모두에서 작동한다는 것을 시사합니다. http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer%28v=VS.90%29.aspx – PaulH

+0

IAbstract가 가지고 있다고 생각합니다. 인터페이스를 직렬화 할 수 없습니다. 그래서 바 대신 ICollection이 바가되도록 List를 변경해야합니다 –

답변

2

XmlSerializer에는 serializable 속성에 setter가 있어야합니다. 그 외에도 XmlSerializer은 인터페이스 속성을 직렬화 할 수 없습니다. 다음 코드는 작동합니다

[XmlElement("Bar")] 
public List<Bar> Bars 
{ 
    get { return bar_; } 
    set { throw new NotSupportedException("This property 'Bars' cannot be set. This property is readonly."); } 
} 

를이 솔루션을 좋아하지 않는 경우에 (예외가 좀 추한) 다음 IXmlSerializable를 구현하고 사용자 정의 직렬화를 작성할 수 있습니다.

편집 :

XmlSerializer를이 IEnumerable를 구현하는 클래스에 특별 대우를 제공합니다 this msdn page에 설명으로 아르투르 Mustafin는 IEnumerable 또는 ICollection는 세터 필요하지 않습니다 구현 오른쪽 회원입니다 또는 ICollection. IEnumerable을 구현하는 클래스는 단일 매개 변수를 사용하는 공개 Add 메서드를 구현해야합니다. Add 메서드의 매개 변수는 GetEnumerator에서 반환 된 값의 Current 속성에서 반환 된 것과 같은 형식이거나 해당 형식의 기본 형식 중 하나 여야합니다. IEnumerable 외에 ICollection (CollectionBase 등)을 구현하는 클래스에는 정수를 사용하는 public Item 인덱싱 된 속성 (C#의 인덱서)이 있어야하며 정수 Count 속성이 정수 여야합니다. Add 메서드에 대한 매개 변수는 Item 속성에서 반환되는 것과 동일한 형식이거나 해당 형식의 기본 형식 중 하나 여야합니다. ICollection을 구현하는 클래스의 경우 일련 번호가 지정된 Item 속성에서 GetEnumerator을 호출하지 않고 serialize 할 값을 검색합니다.

+2

이것은 틀렸고 추한 대답입니다. setter없이 이벤트가 작동하기 때문에 잘못되었습니다. 내 게시물을 참조하십시오. –

+0

XmlSerializer에는 직렬화 가능 속성에 세터 –

3

예외를 throw하기 위해 정답을 부여하면 List<T> 공용 속성에 못생긴 setter를 만들지 않아도됩니다.

List<>은 이미 ICollection<T>을 구현하고 있으며 연속화 메커니즘에 사용되는 이라는 서명이있는 메서드를 제공하기 때문에 발생합니다.

당신은 ICollection<T>List<T>에 연재되는 공용 속성에 세터를 추가하고 변경해야 할 전용 : 당신은 출력 얻을 것이다

[XmlRoot("Foo")] 
public class Foo 
{ 
    private List<Bar> bar_ = new List<Bar>(); 

    [XmlElement("Something")] 
    public string Something { get; set; } 

    [XmlElement("Bar")] 
    public List<Bar> Bars { get { return bar_; } } 
} 

: 또한

<?xml version="1.0" encoding="utf-8"?> 
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Something>My String</Something> 
    <Bar /> 
    <Bar /> 
</Foo> 

를, 그것은이다 메모리 내에서 xml을 직렬화하고 결과를 보거나 테스트하는 것이 더 좋은 아이디어입니다.

static void Main(string[] args) 
{ 
    Bar b1 = new Bar(); 
    // populate b1 with interesting data 
    Bar b2 = new Bar(); 
    // populate b2 with interesting data 

    Foo f = new Foo(); 
    f.Bars.Add(b1); 
    f.Bars.Add(b2); 
    f.Something = "My String"; 

    using (MemoryStream ms = new MemoryStream()) 
    using (System.IO.TextWriter textWriter = new System.IO.StreamWriter(ms)) 
    { 
     System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Foo)); 
     serializer.Serialize(textWriter, f); 
     string text = Encoding.UTF8.GetString(ms.ToArray()); 
     Console.WriteLine(text); 
    } 

    Console.ReadKey(false); 
} 

인터페이스를 사용하여 직렬화하려면 내 프로젝트를 사용하십시오. XmlSerialization

관련 문제