2009-10-24 4 views
29
  • .Net/C# 응용 프로그램에서 나는 서로에 대한 참조가있는 데이터 구조를 가지고 있습니다.
  • 내가 serialize 할 때 .Net은 별도의 개체 복사본으로 모든 참조를 serialize합니다.
  • 다음 예제에서는 'Person'의 배열로 serialize하려고 시도하고 있습니다.
  • 'Person'은 다른 사람을 참조 할 수 있습니다. 동일한 개체에 대한 두 개의 참조가 있기 때문에 위의 코드에서 .net XML 직렬화 - 객체 복사본 대신 참조 저장

    public class Person 
    { 
        public string Name; 
        public Person Friend; 
    } 
    
    Person p1 = new Person(); 
    p1.Name = "John"; 
    
    Person p2 = new Person(); 
    p2.Name = "Mike"; 
    
    p1.Friend = p2; 
    
    Person[] group = new Person[] { p1, p2 }; 
    XmlSerializer ser = new XmlSerializer(typeof(Person[])); 
    using (TextWriter tw = new StreamWriter("test.xml")) 
        ser.Serialize(tw,group); 
    
    //above code generates following xml 
    
    <ArrayOfPerson> 
        <Person> 
        <Name>John</Name> 
        <Friend> 
         <Name>Mike</Name> 
        </Friend> 
        </Person> 
        <Person> 
        <Name>Mike</Name> 
        </Person> 
    </ArrayOfPerson> 
    
  • 같은 '마이크'객체는 두 위치에있다.

  • 직렬화를 해제하는 동안 두 개의 서로 다른 개체가되어 직렬화 될 때 정확한 상태가 아닙니다.
  • 나는 이것을 피하고 serialize 된 xml에있는 객체의 사본 만 갖고 싶습니다. 모든 참조는이 사본을 참조해야합니다. deserialization 후, 나는 같은 오래된 데이터 구조로 돌아가고 싶다.
  • 가능합니까?
+0

BinaryFormatter 및 SoapFormatter가 참조 값을 유지한다는 것을 알게되었습니다. – Palani

+0

SoapFormatter는 더 이상 사용되지 않으며 제네릭을 지원하지 않습니다. –

답변

33

XmlSerializer으로는 불가능합니다. PreserveObjectReferences 속성을 사용하면 DataContractSerializer으로이 작업을 수행 할 수 있습니다. 세부 사항을 설명하는 post을 살펴보십시오.

public class Person 
{ 
    public string Name; 
    public Person Friend; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Person p1 = new Person(); 
     p1.Name = "John"; 

     Person p2 = new Person(); 
     p2.Name = "Mike"; 
     p1.Friend = p2; 
     Person[] group = new Person[] { p1, p2 }; 

     var serializer = new DataContractSerializer(group.GetType(), null, 
      0x7FFF /*maxItemsInObjectGraph*/, 
      false /*ignoreExtensionDataObject*/, 
      true /*preserveObjectReferences : this is where the magic happens */, 
      null /*dataContractSurrogate*/); 
     serializer.WriteObject(Console.OpenStandardOutput(), group); 
    } 
} 

이 다음과 같은 XML이 생성 : 이제 생성자에서 falsePreserveObjectReferences을 설정

<ArrayOfPerson z:Id="1" z:Size="2" xmlns="http://schemas.datacontract.org/2004/07/ToDelete" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"> 
    <Person z:Id="2"> 
     <Friend z:Id="3"> 
      <Friend i:nil="true"/> 
      <Name z:Id="4">Mike</Name> 
     </Friend> 
     <Name z:Id="5">John</Name> 
    </Person> 
    <Person z:Ref="3" i:nil="true"/> 
</ArrayOfPerson> 

을하고 당신이 얻을 것이다 :

<ArrayOfPerson xmlns="http://schemas.datacontract.org/2004/07/ToDelete" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <Person> 
     <Friend> 
      <Friend i:nil="true"/> 
      <Name>Mike</Name> 
     </Friend> 
     <Name>John</Name> 
    </Person> 
    <Person> 
     <Friend i:nil="true"/> 
     <Name>Mike</Name> 
    </Person> 
</ArrayOfPerson> 

여기

은 샘플 코드입니다 이 방법으로 생성 된 XML은 상호 운용 할 수 없다는 점을 언급 할 필요가 있습니다. DataContractSerializer로만 역 직렬화 할 수 있습니다 ( BinaryFormatter과 동일한 설명).

4

ExtendedXmlSerializer를 사용할 수 있습니다.

public class Person 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public Person Boss { get; set; } 
} 

public class Company 
{ 
    public List<Person> Employees { get; set; } 
} 

다음과 같이 순환 참조로 객체를 생성 : 당신은 참조 객체로 Person 클래스를 구성해야합니다

var boss = new Person {Id = 1, Name = "John"}; 
boss.Boss = boss; //himself boss 
var worker = new Person {Id = 2, Name = "Oliver"}; 
worker.Boss = boss; 
var obj = new Company 
{ 
    Employees = new List<Person> 
    { 
     worker, 
     boss 
    } 
}; 

당신은 클래스가있는 경우 여기에 직렬화 object reference and circular reference

의 예입니다 :

var serializer = new ConfigurationContainer().ConfigureType<Person>() 
              .EnableReferences(p => p.Id) 
              .Create(); 

마지막으로 obj를 직렬화 할 수 있습니다. 요법 :

var xml = serializer.Serialize(obj); 

출력 XML은 다음과 같이 표시됩니다

<?xml version="1.0" encoding="utf-8"?> 
<Company xmlns="clr-namespace:ExtendedXmlSerializer.Samples.ObjectReference;assembly=ExtendedXmlSerializer.Samples"> 
    <Employees> 
    <Capacity>4</Capacity> 
    <Person Id="2"> 
     <Name>Oliver</Name> 
     <Boss Id="1"> 
     <Name>John</Name> 
     <Boss xmlns:exs="https://extendedxmlserializer.github.io/v2" exs:entity="1" /> 
     </Boss> 
    </Person> 
    <Person xmlns:exs="https://extendedxmlserializer.github.io/v2" exs:entity="1" /> 
    </Employees> 
</Company> 

ExtendedXmlSerializer 지원 .NET 4.5 및 .NET 코어.

+0

당신은 자신의 소프트웨어를 홍보하고 있다고 언급해야합니다. 그것은 좋은 일을하는 것처럼 보이지만 .net 프레임 워크의 일부가 아닙니다. – MikeT