2010-09-28 13 views
18

XMLSerialization का उपयोग कर ऑब्जेक्ट को क्रमबद्ध करने का प्रयास करते समय मुझे निम्न अपवाद प्राप्त हो रहा है।एक्सएमएल सीरियलाइजेशन का उपयोग करते समय परिपत्र संदर्भ?

A circular reference was detected while serializing an object of type MyObject}

मुझे पता है वृत्तीय संदर्भ है, क्योंकि ObjectA ObjectB के childObject हो सकता है और ObjectB के parentObject ObjectA है, लेकिन मुझे लगता है कि संदर्भ रखने के लिए यदि संभव हो तो करना चाहते हैं। क्या इस ऑब्जेक्ट को सीरियलाइज़ेशन प्रक्रिया के दौरान किसी भी डेटा को खोए बिना एक्सएमएल सीरियलाइजेशन के साथ क्रमबद्ध करने का कोई तरीका है? मैं serialization के साथ बहुत familar नहीं हूँ इसलिए मैं उम्मीद कर रहा हूँ कि कुछ प्रकार की विशेषता मैं सेट कर सकता हूं।

उत्तर

23

सीरिएलाइज़र प्रकार के आधार पर कई विकल्प हैं।

आप DataContractSerializer या BinaryFormatter इस्तेमाल कर सकते हैं तो आप OnSerializedAttribute और जनक गुण सेट अपने बच्चे को वस्तु के लिए यह करने के लिए उपयोग कर सकते हैं:

[Serializable] 
public class Child 
{ 
    public string Foo { get; set; } 

    public Parent Parent { get { return parent; } set { parent = value; } } 

    // We don't want to serialize this property explicitly. 
    // But we could set it during parent deserialization 
    [NonSerialized] 
    private Parent parent; 
} 

[Serializable] 
public class Parent 
{ 
    // BinaryFormatter or DataContractSerializer whould call this method 
    // during deserialization 
    [OnDeserialized()] 
    internal void OnSerializedMethod(StreamingContext context) 
    { 
     // Setting this as parent property for Child object 
     Child.Parent = this; 
    } 

    public string Boo { get; set; } 

    public Child Child { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Child c = new Child { Foo = "Foo" }; 
     Parent p = new Parent { Boo = "Boo", Child = c }; 

     using (var stream1 = new MemoryStream()) 
     { 
      DataContractSerializer serializer = new DataContractSerializer(typeof (Parent)); 
      serializer.WriteObject(stream1, p); 
      stream1.Position = 0; 
      var p2 = (Parent)serializer.ReadObject(stream1); 

      Console.WriteLine(object.ReferenceEquals(p, p2)); //return false 
      Console.WriteLine(p2.Boo); //Prints "Boo" 

      //Prints: Is Parent not null: True 
      Console.WriteLine("Is Parent not null: {0}", p2.Child.Parent != null); 
     } 
    } 

} 

आप XmlSerializer उपयोग करने के लिए आप, IXmlSerializable को लागू करना चाहिए XmlIgnoreAttribute का उपयोग करना चाहते हैं और अधिक लागू किए या ReadXml विधि में एक ही तर्क कम है। लेकिन इस मामले में आप मैन्युअल रूप से भी सभी XML क्रमांकन तर्क को लागू करना चाहिए:

[Serializable] 
public class Child 
{ 
    public Child() 
    { 
    } 

    public string Foo { get; set; } 

    [XmlIgnore] 
    public Parent Parent { get; set; } 
} 

[Serializable] 
public class Parent 
{ 
    public Parent() 
    { 
    } 

    #region IXmlSerializable Members 

    public System.Xml.Schema.XmlSchema GetSchema() 
    { 
     throw new NotImplementedException(); 
    } 

    public void ReadXml(System.Xml.XmlReader reader) 
    { 
     //Reading Parent content 
     //Reading Child 
     Child.Parent = this; 
    } 

    public void WriteXml(System.Xml.XmlWriter writer) 
    { 
     //Writing Parent and Child content 
    } 

    #endregion 

    public string Boo { get; set; } 

    public Child Child { get; set; } 
} 
+0

यदि मैं ऐसा करता हूं तो ऑब्जेक्ट को deserialize जब संदर्भ चला गया है। ऑब्जेक्ट डब्लूसीएफ सेवा – Rachel

+1

से आ रहा है धन्यवाद! आपके संपादन ने स्पष्ट चीजों को स्पष्ट किया ... मैं पूरी तरह से भूल गया कि मैं अभिभावक '[ऑनडिसेरियलाइजिंग()] 'जोड़ सकता हूं, जो मैंने किया है। – Rachel

+0

जैसा कि मैंने एएचएम के उत्तर टिप्पणी के साथ उल्लेख किया है, इस मामले में OnDeserializingAttribute अनावश्यक है, क्योंकि यह अभी भी इसके बिना ठीक काम करता है। लेकिन आप अभी भी इस विधि में कुछ अतिरिक्त तर्क जोड़ सकते हैं। –

1

अभिभावक ऑब्जेक्ट संपत्ति को [NonSerialized] के रूप में चिह्नित करें।

http://blog.kowalczyk.info/article/Serialization-in-C.html

+0

अगर मैं यह तो NonSerialized डेटा एक बार चला गया है मैं वस्तु deserialize निशान। – Rachel

+0

गैर-सीरियलाइज्ड का उपयोग XmlSerializer –

2

आप XmlSerializer के बजाय DataContractSerializer का उपयोग कर सकते हैं तो आप DataContract विशेषता पर IsReference संपत्ति का उपयोग कर सकते हैं। इसे सक्षम करने से संदर्भ बनाए जाएंगे, ताकि वे deserialization पर पुनर्निर्मित किया जाएगा।

डेटाकंट्रैक्टसेरियलाइज़र भी एक्सएमएल को क्रमबद्ध करता है, लेकिन आउटपुट की तरह दिखने पर आपके पास कुछ कम नियंत्रण होता है, कि आप पुराने XMLSerializer के साथ करते हैं। आप यहां serializers के बारे में अधिक पढ़ सकते हैं: http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/

+0

द्वारा नहीं किया जाता है, धन्यवाद, मैं इसे देख लूंगा। क्या आपके पास एक उदाहरण है कि मैं उस वर्ग को उस वर्ग पर कैसे सेट करूंगा जो '[DataContract] 'के रूप में परिभाषित किए जाने के बजाय' [Serializable] 'विशेषता के रूप में है? – Rachel

+0

उह '[डेटाकंट्रैक्ट]' विशेषताओं पर स्विच किए बिना ऐसा करने का कोई तरीका ढूंढने का प्रयास कर रहा है .... मेरी बेस क्लास सबकुछ के लिए उपयोग की जाती है और यदि मैं इसे संशोधित करता हूं, तो मुझे अपने ऑब्जेक्ट लाइब्रेरी में लगभग सभी वर्गों को ' [DataContract] '' [Serializable] 'के बजाय 'और सभी गुणों के लिए' [डेटामेम्बर] 'विशेषता जोड़ें और इस बात को लेकर कोई संकेत नहीं है कि यह तेज़ कैसे करें ... – Rachel

+0

आप डेटाकंट्रैक्ट पर स्विच किए बिना ऐसा नहीं कर सकते हैं। यह सिर्फ समर्थित नहीं है। यदि आप Serializable विशेषता का उपयोग करना चाहते हैं, तो आपको सर्गेई सुझावों की तरह कुछ करना होगा, और deserialization के बाद संदर्भों को ठीक करने के लिए कुछ कोड कॉल करें। – AHM

संबंधित मुद्दे