2009-10-24 12 views
29
  • .Net/C#アプリケーションでは、私は互いに参照を持つデータ構造を持っています。
  • シリアル化すると、.Netは別のオブジェクトコピーを持つすべての参照をシリアル化します。
  • 次の例では、「Person」の配列にシリアル化しようとしています
  • 「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> 
    
  • 同じオブジェクトに対して2つの参照があるので、同じ「マイク」の目的は、二つの場所です。

  • デシリアライズ中に、それらは2つの異なるオブジェクトになります。これらのオブジェクトは、シリアル化されたときの正確な状態ではありません。
  • 私はこれを避け、シリアル化されたxmlでオブジェクトのコピーを持ちたいと思います。すべての参照はこのコピーを参照する必要があります。デシリアライズ後、私は元の同じデータ構造に戻りたいと思う。
  • 可能でしょうか?
+0

BinaryFormatterとSoapFormatterが参照値を保持していることがわかりました。 – Palani

+0

SoapFormatterは非推奨であり、ジェネリックはサポートしていません。 –

答えて

33

XmlSerializerでは不可能です。 PreserveObjectReferencesプロパティを使用してDataContractSerializerでこれを達成できます。詳細を説明しているpostをご覧ください。ここで

はサンプルコードです:

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

今すぐコンストラクタでfalsePreserveObjectReferencesを設定し、この取得します:

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

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を生成しますこのようにして生成された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; } 
} 

、あなたはこのように、循環参照を持つオブジェクトを作成します:ここでは、クラスを持っている場合は直列化の例object reference and circular reference

ある

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

あなたは、参照オブジェクトとしてPersonクラスを設定する必要があります:

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

最後に、あなたのobjをシリアル化することができます電気ショック療法:

<?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のコア:

var xml = serializer.Serialize(obj); 

出力XMLは次のようになります。

+0

あなたはあなた自身のソフトウェアを宣伝していることを言及する必要があります。これは、.netフレームワークの一部ではありませんが、良い仕事のように見えます – MikeT

関連する問題