2009-10-24 27 views
29
  • Trong .Net/C# Ứng dụng, tôi có cấu trúc dữ liệu có tham chiếu với nhau.
  • Khi tôi tuần tự hóa chúng, .Net Nối tiếp tất cả các tham chiếu với các bản sao đối tượng riêng biệt.
  • Trong ví dụ sau, tôi đang cố gắng tuần tự hóa thành mảng 'Person'
  • Một 'Người' có thể có tham chiếu đến một người khác.Nối tiếp XML trên mạng - Lưu trữ tham chiếu thay vì Sao chép đối tượng

    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> 
    
  • Trong đoạn mã trên, các 'Mike' cùng một đối tượng đang có trên hai nơi, vì có hai tài liệu tham khảo cho cùng một đối tượng.

  • Trong khi deserializing, chúng trở thành hai đối tượng khác nhau, không phải là trạng thái chính xác khi chúng được tuần tự hóa.
  • Tôi muốn tránh điều này và chỉ có bản sao của đối tượng trong xml được tuần tự hóa và tất cả các tham chiếu nên tham chiếu đến bản sao này. Sau khi deserialization, tôi muốn lấy lại, cùng một cấu trúc dữ liệu cũ.
  • Có thể không?
+0

Chỉ thấy BinaryFormatter và SoapFormatter giữ nguyên giá trị tham chiếu. – Palani

+0

SoapFormatter đã không được chấp nhận và nó không hỗ trợ Generics. –

Trả lời

33

Không thể với XmlSerializer. Bạn có thể đạt được điều này với DataContractSerializer bằng cách sử dụng thuộc tính PreserveObjectReferences. Bạn có thể xem qua số post để giải thích chi tiết.

Dưới đây là một số mẫu mã:

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); 
    } 
} 

này tạo ra XML sau:

<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> 

Bây giờ thiết lập PreserveObjectReferences-false trong constructor và bạn sẽ có được điều này:

<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> 

Điều đáng nói đến là XML được tạo ra theo cách này không tương thích được và chỉ có thể được deserialized với một DataContractSerializer (cùng một nhận xét như với BinaryFormatter).

4

Bạn có thể sử dụng ExtendedXmlSerializer. Dưới đây là một ví dụ về serialization object reference and circular reference

Nếu bạn có một lớp:

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; } 
} 

sau đó bạn tạo đối tượng với tham chiếu vòng tròn, như thế này:

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 
    } 
}; 

Bạn phải cấu hình lớp người như đối tượng tham khảo :

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

Cuối cùng, bạn có thể tuần tự hóa obj của mình vv:

var xml = serializer.Serialize(obj); 

Output xml sẽ giống như thế này:

<?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 hỗ trợ .net 4.5 và Net Core.

+0

bạn nên đề cập rằng bạn đang quảng cáo phần mềm của riêng mình, đó không phải là một phần của khung .net mặc dù trông giống như một chút công việc – MikeT

Các vấn đề liên quan