2009-08-18 25 views
29

मेरे पास कई कक्षाएं हैं जो प्रारंभिक मान सेट होने के बाद अपरिवर्तनीय हैं। एरिक लिपर्ट ने यह write-once immutability पर कॉल किया।अपरिवर्तनीयता और एक्सएमएल सीरियलाइजेशन

लिखने के कार्यान्वयन - एक बार सी # में अपरिवर्तनीयता आमतौर पर निर्माता के माध्यम से प्रारंभिक मान निर्धारित करने का मतलब है। ये मान केवल पढ़ने वाले फ़ील्ड को प्रारंभ करते हैं।

लेकिन यदि आपको XmlSerializer या DataContractSerializer का उपयोग करके एक्सएमएल को इस तरह की कक्षा को क्रमबद्ध करने की आवश्यकता है, तो आपके पास पैरामीटर रहित कन्स्ट्रक्टर होना चाहिए।

क्या किसी को इस समस्या के आसपास काम करने के लिए सुझाव हैं? क्या अपरिवर्तनीयता के अन्य रूप हैं जो क्रमबद्धरण के साथ बेहतर काम करते हैं?

संपादित करें: जैसा कि @Todd ने इंगित किया है, DataContractSerializer को पैरामीटर रहित कन्स्ट्रक्टर की आवश्यकता नहीं है। DataContractSerializer documentation on MSDN के अनुसार, DataContractSerializer "लक्ष्य ऑब्जेक्ट के निर्माता को कॉल नहीं करता है।"

+1

मुझे लगता है कि आप चीजों को भ्रमित कर रहे हैं ... आप जो वर्णन करते हैं वह पॉपसिकल अपरिवर्तनीयता है। यह लिखने की तरह दिखता है-एक बार अपरिवर्तनीयता। –

+0

संपादित करें: ... ** ** ** popsicle नहीं है ... –

+0

आप बिल्कुल सही हैं, @Martinho। मैंने अपने प्रश्न को "लिखने के लिए एक बार अपरिवर्तनीयता" पढ़ने के लिए सही किया है। – dthrasher

उत्तर

9

यह मानते हुए अपने "अपरिवर्तनीय" वस्तु है:

public class Immutable 
{ 
    public Immutable(string foo, int bar) 
    { 
     this.Foo = foo; 
     this.Bar = bar; 
    } 

    public string Foo { get; private set; } 
    public int Bar { get; private set; } 
} 

आप क्रमांकन/deserialization के दौरान कि अपरिवर्तनीय वस्तु का प्रतिनिधित्व करने के एक डमी वर्ग बना सकते हैं:

public class DummyImmutable 
{ 
    public DummyImmutable(Immutable i) 
    { 
     this.Foo = i.Foo; 
     this.Bar = i.Bar; 
    } 

    public string Foo { get; set; } 
    public int Bar { get; set; } 

    public Immutable GetImmutable() 
    { 
     return new Immutable(this.Foo, this.Bar); 
    } 
} 

आप प्रकार की कोई संपत्ति है, जब अपरिवर्तनीय, इसे क्रमबद्ध न करें, और इसके बजाय एक डमी को क्रमबद्ध करें:

[XmlIgnore] 
public Immutable SomeProperty { get; set; } 

[XmlElement("SomeProperty")] 
public DummyImmutable SomePropertyXml 
{ 
    get { return new DummyImmutable(this.SomeProperty); } 
    set { this.SomeProperty = value != null ? value.GetImmutable() : null; } 
} 

ठीक है, यह कुछ आसान लगता है जो बहुत आसान दिखता है ... लेकिन इसे काम करना चाहिए;)

+2

यह बुरा है, लेकिन माइक्रोसॉफ्ट द्वारा अनुशंसित दृष्टिकोण प्रतीत होता है। –

8

"रीयलियो-ट्रुलियो" अपरिवर्तनीयता में निर्माता शामिल है। Popsicle अचल स्थिति है जहाँ आप, उदाहरण के लिए कर सकते हैं:

Person p = new Person(); 
p.Name = "Fred"; 
p.DateOfBirth = DateTime.Today; 
p.Freeze(); // **now** immutable (edit attempts throw an exception) 

(या एक ऑब्जेक्ट प्रारंभकर्ता के साथ एक ही)

यह DataContractSerializer फिट बैठता है बहुत अच्छी तरह से है, जब तक आप पर धारावाहिक कॉलबैक करने के लिए करने के लिए संभाल के रूप में FreezeXmlSerializer क्रमबद्ध कॉलबैक नहीं करता है, इसलिए अधिक काम है।

या तो यदि आप कस्टम सीरियलाइजेशन (IXmlSerializable) का उपयोग करते हैं तो कोई भी उपयुक्त होगा। इसी प्रकार, कस्टम क्रमबद्धता व्यापक रूप से रीयलियो-ट्र्यूलियो अपरिवर्तनीयता के साथ करने योग्य है, लेकिन दर्दनाक है - और यह एक झूठ है, क्योंकि यह "एक बार बना है, फिर इंटरफ़ेस कॉल करें" - इसलिए वास्तव में ठीक से अपरिवर्तनीय नहीं है।

वास्तविक अपरिवर्तनीयता के लिए, एक डीटीओ का उपयोग करें।

+0

'रीयलियो-ट्रुलियो' अपरिवर्तनीयता क्या है? –

+1

@ChibuezeOpata कुछ * वास्तव में * अपरिवर्तनीय (कम से कम, बिना धोखाधड़ी के) - 'readonly', आदि –

+0

हाहा, अच्छा, धन्यवाद! :) –

0

मैंने अभी आपके द्वारा लिंक किए गए आलेख पर एक नज़र डाली थी। अपनी शब्दावली में, कन्स्ट्रक्टर में शुरू किए गए रीडोनली फ़ील्ड का उपयोग करने वाली वस्तुओं को "केवल-लिखने योग्य अपरिवर्तनीयता" कहा जाता है।

"पोप्सिकल अपरिवर्तनीयता" थोड़ा अलग है। लिपर्ट दो उदाहरण देता है जहां यह उपयोगी होगा: deserialization (जिस समस्या को आप हल करने की कोशिश कर रहे हैं), और परिपत्र संदर्भ जहां ए और बी को स्वतंत्र रूप से बनाया जाना चाहिए, लेकिन किसी की जरूरत बी के संदर्भ में है, और बी के संदर्भ में बी ।

इस परिणाम को प्राप्त करने के दो और स्पष्ट तरीकों का उल्लेख यहां किया गया है (जैसा कि मैं वास्तव में यह लिख रहा था)। थॉमस लेवेस्क का पैटर्न मूल रूप से "बिल्डर" पैटर्न है। लेकिन यह इस मामले में बल्कि अनावश्यक रूप से है क्योंकि आपको न केवल बिल्डर से इमटेबल तक जाना है, बल्कि अपरिवर्तनीय से बिल्डर तक भी जाना है ताकि धारावाहिक/deserialization सममित है।

तो मार्क ग्रेवल द्वारा वर्णित "लॉक" पैटर्न, अधिक उपयोगी लगता है। हालांकि मैं सी # से परिचित नहीं हूं, इसलिए मुझे यकीन नहीं है कि इसे कैसे कार्यान्वित किया जाए। मुझे लगता है कि शायद लॉक लॉक की गई एक निजी संपत्ति। फिर सभी गेटर विधियों को स्पष्ट रूप से जांचने की आवश्यकता है कि ऑब्जेक्ट लॉक है (उर्फ "जमे हुए") अभी तक। यदि ऐसा है तो उन्हें एक अपवाद फेंकना चाहिए (यह एक रनटाइम त्रुटि है; आप संकलन समय पर पॉपस्टिक अपरिवर्तनीयता को लागू नहीं कर सकते हैं)।

+0

धन्यवाद, टोड। मैंने अपने प्रश्न को "लिखने के लिए" अपरिवर्तनीयता को पढ़ने के लिए सही किया है। मैं DataContractSerializer के साथ एक फ्रीज विधि का उपयोग कर जांच करूंगा। – dthrasher

+0

मेरे दूसरे (दूसरे) उत्तर पर एक नज़र डालें। यदि DataContractSerializer निजी सदस्यों को deserialize कर सकते हैं तो आपको "popsicle अपरिवर्तनीयता" या एक फ्रीज() विधि की आवश्यकता नहीं है। –

2

मैं यहां चर्चा पर एक नज़र डालने की सलाह देता हूं: Why XML-Serializable class need a parameterless constructor

आपको DataContractSerializer का उपयोग करने पर विचार करना चाहिए। जहां तक ​​मैं दस्तावेज़ों से कह सकता हूं, इसे पैरामीटर रहित कन्स्ट्रक्टर की आवश्यकता नहीं है, और निजी सदस्यों को क्रमबद्ध/deserialize कर सकते हैं।

+0

आप सही हैं, टोड। एमएसडीएन के अनुसार, DataContractSerializer कन्स्ट्रक्टर को कॉल नहीं करता है: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx – dthrasher

+0

ध्यान दें कि DataContractSerializer केवल .NET 3.5 के बाद उपलब्ध है। आप इसे .NET 2.0 – Maxence

6

यदि कक्षा वास्तव में अपरिवर्तनीय है, तो विशेषताओं के साथ चिह्नित सार्वजनिक पाठक फ़ील्ड का उपयोग करें।

[DataContract()] 
public class Immutable 
{ 
     [DataMember(IsRequired=true)] 
     public readonly string Member; 

     public Immutable(string member) 
     { 
      Member = member; 
     } 
} 
+0

आह के साथ उपयोग नहीं कर सकते हैं, यह! सार्वजनिक क्षेत्र! इसे संपत्तियों से काम करने की कोशिश कर रहा है ... इस अंतर्निहित उत्तर के लिए धन्यवाद (हाँ, मुझे पता है कि यह 5 साल बाद है) –

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