क्यों XML-Serializable वर्ग को एक पैरामीटर रहित निर्माता की आवश्यकता होती है


173

मैं Xml क्रमांकन करने के लिए कोड लिख रहा हूं। नीचे समारोह के साथ।

public static string SerializeToXml(object obj)
{
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
    using (StringWriter writer = new StringWriter())
    {
        serializer.Serialize(writer, obj);
        return writer.ToString();
    }
}

यदि तर्क पैरामीटर रहित कंस्ट्रक्टर के बिना वर्ग का एक उदाहरण है, तो यह एक अपवाद फेंक देगा।

अखंडित अपवाद: System.InvalidOperationException: CSharpConsole.Foo क्रमबद्ध नहीं किया जा सकता क्योंकि इसमें एक पैरामीटर रहित निर्माता नहीं है। System.Xml.Serialization.TypeDesc.CheckSupported () System.Xml.Serialization.TypeScope.GetTypeDesc पर टाइप करें (Type type, MemberInfo sourc e, BoolD DirectReference, Boolean फेंकऑनएयर) System.Xml.Serialization.ModScopeGope। System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping पर बूलियन प्रत्यक्ष संदर्भ) (Type type, XmlRootAttribute root, String defaultNamespace) System.Xml.Serialization.XmlSerializer..ctor (प्रकार प्रकार, स्ट्रिंग DefaultName space) को सिस्टम .Xml पर। XmlSerializer..ctor (प्रकार प्रकार)

Xml क्रमांकन को सफल करने की अनुमति देने के लिए एक पैरामीटर रहित निर्माता क्यों होना चाहिए?

EDIT: cfeduke के उत्तर के लिए धन्यवाद। पैरामीटर रहित कंस्ट्रक्टर निजी या आंतरिक हो सकता है।


1
यदि आप रुचि रखते हैं, तो मैंने पाया कि बिना निर्माता की आवश्यकता के वस्तुओं को कैसे बनाया जाए (अपडेट देखें) - लेकिन इससे XmlSerializer बिल्कुल भी मदद नहीं करेगा - यह अभी भी इसकी मांग करता है। कस्टम कोड के लिए उपयोगी, हो सकता है।
मार्क Gravell

1
XmlSerializerडिसेरिएलाइज़ेशन के लिए डिफ़ॉल्ट पैरामीटर रहित निर्माता की आवश्यकता होती है।
अमित कुमार घोष

जवाबों:


243

किसी वस्तु के क्रम-निर्धारण के दौरान, किसी वस्तु को क्रमबद्ध करने के लिए जिम्मेदार वर्ग क्रमबद्ध वर्ग का एक उदाहरण बनाता है और फिर अनुक्रमित फ़ील्ड और गुणों को पॉप्युलेट करने के लिए प्राप्त करने के बाद ही आगे बढ़ता है।

आप अपना कंस्ट्रक्टर बना सकते हैं privateया internalयदि आप चाहते हैं, तो बस जब तक यह पैरामीटर रहित है।


1
ओह, इसलिए, मैं पैरामीटर रहित ctor को निजी या आंतरिक बना सकता हूँ और क्रमांकन अभी भी काम करता है। आपके उत्तर के लिए धन्यवाद।
मॉर्गन चेंग

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

14
एक्सेसिबिलिटी टिप एक अच्छा है, लेकिन आपकी व्याख्या धारावाहिकता के लिए कोई मतलब नहीं रखती है। एक वस्तु को केवल डी-सीरियलाइजेशन के लिए बनाने की आवश्यकता है। मुझे अनुमान है कि टाइप-चेक कोड XmlSerializer कंस्ट्रक्टर में बनाया गया है क्योंकि दोनों ही तरीकों से एक ही उदाहरण का उपयोग किया जा सकता है।
तोमर गेबल

7
@jwg एक उदाहरण है जब आप अपने XML को किसी प्रकार की वेब सेवा में भेज रहे हैं और उन वस्तुओं को अपने घटक में प्राप्त करने में रुचि नहीं रखते हैं।
तोमर गबेल

5
ध्यान रखें कि भले ही आप अपने पैरामीटर को निर्मूलक बनाते हैं privateया internal, आपके सभी गुण जिनके मूल्यों को क्रमबद्ध किया गया था, उनमें बसने चाहिए public
चर्नोला

75

यह एक सीमा है XmlSerializer। ध्यान दें कि BinaryFormatterऔर DataContractSerializer इसके लिए आवश्यकता नहीं है - वे ईथर से बाहर एक अनैच्छिक वस्तु बना सकते हैं और deserialization के दौरान इसे प्रारंभ कर सकते हैं।

चूँकि आप xml का उपयोग कर रहे हैं, आप DataContractSerializerअपनी कक्षा का उपयोग [DataContract]/ और उसके साथ अंकन पर विचार कर सकते हैं [DataMember, लेकिन ध्यान दें कि यह स्कीमा को बदलता है (उदाहरण के लिए, कोई समान नहीं है [XmlAttribute]- सब कुछ तत्व बन जाता है)।

अद्यतन: यदि आप वास्तव में जानना चाहते हैं, तो निर्माणकर्ता को आमंत्रित किए बिना ऑब्जेक्ट बनाने के लिए BinaryFormatterएट अल का उपयोग FormatterServices.GetUninitializedObject()करें। शायद खतरनाक; मैं इसे अक्सर इस्तेमाल करने की सलाह नहीं देता; - MSDN पर टिप्पणी भी देखें:

क्योंकि ऑब्जेक्ट का नया उदाहरण शून्य पर आरंभीकृत किया गया है और कोई भी कंस्ट्रक्टर नहीं चलाया जाता है, तो ऑब्जेक्ट उस स्थिति का प्रतिनिधित्व नहीं कर सकता है जिसे उस ऑब्जेक्ट द्वारा मान्य माना जाता है। वर्तमान विधि का उपयोग केवल डीरिएरलाइजेशन के लिए किया जाना चाहिए जब उपयोगकर्ता सभी क्षेत्रों को तुरंत आबाद करना चाहता है। यह एक असिंचित स्ट्रिंग नहीं बनाता है, क्योंकि एक अपरिवर्तनीय प्रकार की खाली आवृत्ति बनाने से कोई उद्देश्य नहीं होता है।

मेरा अपना सीरियलाइज़ेशन इंजन है, लेकिन मैं इसे इस्तेमाल करने का इरादा नहीं रखता FormatterServices; मुझे यह जानना काफी पसंद है कि एक कंस्ट्रक्टर ( कोई भी कंस्ट्रक्टर) वास्तव में निष्पादित किया गया है।


FormatterServices.GetUninitializedObject (प्रकार) के बारे में टिप के लिए धन्यवाद। :)
ओमेर वैन क्लोएटन

6
हे; यह पता चलता है कि मैं अपनी सलाह का पालन नहीं करता हूं; प्रोटोबुफ़-नेट ने (वैकल्पिक रूप से) उम्र केFormatterServices लिए उपयोग की अनुमति दी है
मार्क ग्रेवेल

1
लेकिन जो मुझे समझ में नहीं आता है, उस मामले में कोई निर्माता निर्दिष्ट नहीं है, कंपाइलर एक सार्वजनिक पैरामीटर रहित निर्माता बनाता है। तो क्यों xml deserialization इंजन के लिए इतना अच्छा नहीं है?
toddmo

अगर मैं XML को डिस्क्राइबलाइज़ करना चाहता हूं और उनके कंस्ट्रक्टर का उपयोग करके कुछ ऑब्जेक्ट को इनिशियलाइज़ करना चाहता हूं (ताकि कंस्ट्रक्टर के माध्यम से एलीमेंट्स / एट्रिब्यूट्स उपलब्ध हों), तो क्या इसे हासिल करने का कोई तरीका है? क्या सीरियलाइज़ेशन प्रक्रिया को अनुकूलित करने का कोई तरीका नहीं है ताकि यह अपने बिल्डरों का उपयोग करके वस्तुओं का निर्माण करे?
शिम्मी वेइटहंडलर

1
@ शमी नोप; यह समर्थित नहीं है। वहाँ है IXmlSerializable , लेकिन: एक जो कि कंस्ट्रक्टर के बाद होता है , और बी: यह बहुत ही बदसूरत और सही पाने के लिए कठिन है (विशेष रूप से डिसेरिअलाइज़ेशन) - मैं दृढ़ता से इसे लागू करने की कोशिश करने के खिलाफ सलाह देता हूं, लेकिन: यह आपको कंस्ट्रक्टर का उपयोग करने की अनुमति नहीं देगा
मार्क Gravell

4

इसका उत्तर है: बिना किसी अच्छे कारण के।

अपने नाम के विपरीत, XmlSerializerवर्ग का उपयोग न केवल क्रमांकन के लिए किया जाता है, बल्कि deserialization के लिए भी किया जाता है। यह सुनिश्चित करने के लिए आपकी कक्षा में कुछ जाँचें करता है कि यह काम करेगा, और उनमें से कुछ जाँचें केवल deserialization के लिए उचित हैं, लेकिन यह उन सभी को वैसे भी निष्पादित करता है, क्योंकि यह नहीं जानता कि आप बाद में क्या करने का इरादा रखते हैं।

आपकी कक्षा उत्तीर्ण करने में विफल रहने वाली जाँच उन जाँचों में से एक है जो केवल निर्जनीकरण के लिए प्रासंगिक हैं। यहाँ होता है:

  • डिसेरिएलाइज़ेशन के दौरान, XmlSerializerक्लास को आपके प्रकार के उदाहरण बनाने की आवश्यकता होगी।

  • किसी प्रकार का एक उदाहरण बनाने के लिए, उस प्रकार के एक निर्माता को इनवॉइस करने की आवश्यकता होती है।

  • यदि आपने एक कंस्ट्रक्टर घोषित नहीं किया है, तो कंपाइलर पहले से ही एक डिफ़ॉल्ट पैरामीटर रहित कंस्ट्रक्टर की आपूर्ति कर चुका है, लेकिन यदि आपने एक कंस्ट्रक्टर घोषित किया है, तो वह एकमात्र कंस्ट्रक्टर उपलब्ध है।

  • इसलिए, यदि आप जिस कंस्ट्रक्टर को पैरामीटर घोषित करते हैं, तो आपकी क्लास को तुरंत एंज्वाय करने का एकमात्र तरीका उस कंस्ट्रक्टर को शामिल करना है जो मापदंडों को स्वीकार करता है।

  • हालांकि, XmlSerializerकिसी भी निर्माणकर्ता को एक पैरामीटरविहीन निर्माणकर्ता को छोड़कर आमंत्रित करने में सक्षम नहीं है, क्योंकि यह नहीं जानता कि मापदंडों को स्वीकार करने वाले निर्माणकर्ताओं के पास क्या पैरामीटर हैं। इसलिए, यह देखने के लिए जांचता है कि क्या आपकी कक्षा में एक पैरामीटर रहित कंस्ट्रक्टर है, और चूंकि यह नहीं है, यह विफल रहता है।

इसलिए, यदि XmlSerializerवर्ग को इस तरह लिखा गया था कि केवल क्रमबद्धता के लिए चेक का प्रदर्शन किया जाए, तो आपकी कक्षा उत्तीर्ण हो जाएगी, क्योंकि क्रमबद्धता के बारे में बिल्कुल कुछ भी नहीं है जो कि एक पैरामीटर रहित निर्माणकर्ता होना आवश्यक है।

जैसा कि दूसरों ने पहले ही बताया है, आपकी समस्या का त्वरित समाधान बस एक पैरामीटर रहित निर्माणकर्ता को जोड़ना है। दुर्भाग्य से, यह भी एक गंदा समाधान है, क्योंकि इसका मतलब है कि आपके पास कोई भी readonlyसदस्य कंस्ट्रक्टर मापदंडों से आरंभिक नहीं हो सकता है ।

इन सब के अलावा, XmlSerializerक्लास को इस तरह से लिखा जा सकता था जैसे कि बिना पैरामीटर वाले कंस्ट्रक्टरों के वर्गों के डीरिएलाइज़ेशन की अनुमति देना। यह सब "फैक्टरी विधि डिजाइन पैटर्न" (विकिपीडिया) का उपयोग करने के लिए होगा । इसके लुक से, माइक्रोसॉफ्ट ने तय किया कि यह डिज़ाइन पैटर्न डॉटनेट प्रोग्रामर्स के लिए बहुत उन्नत है, जिन्हें स्पष्ट रूप से ऐसी चीजों के साथ अनावश्यक रूप से भ्रमित नहीं होना चाहिए। इसलिए, डॉटनेट प्रोग्रामर्स को Microsoft के अनुसार, पैरामीटर रहित कंस्ट्रक्टरों से बेहतर रहना चाहिए।


Lol आप कहते हैं, For no good reason whatsoever,तो कहने के लिए जाओ, XmlSerializer is not capable of invoking any constructor except a parameterless constructor, because it does not know what parameters to pass to constructors that accept parameters.अगर यह नहीं जानता कि एक निर्माता को क्या पैरामीटर पास करना है, तो यह कैसे पता चलेगा कि किसी कारखाने में क्या पैरामीटर पास करना है? या किस कारखाने का उपयोग करना है? मैं इस उपकरण का उपयोग करने के लिए और अधिक सरल होने की कल्पना नहीं कर सकता - आप एक वर्ग deserialized चाहते हैं, तो deserializer को एक डिफ़ॉल्ट उदाहरण बनाने दें और फिर आपके द्वारा टैग किए गए प्रत्येक फ़ील्ड को पॉप्युलेट करें। आसान।
चक

0

सबसे पहले, यह प्रलेखन में लिखा गया है । मुझे लगता है कि यह आपके वर्ग के क्षेत्रों में से एक है, न कि मुख्य एक - और आप इसे वापस w / o पैरामीटर निर्माण के लिए deserialiser कैसे चाहते हैं?

मुझे लगता है कि कंस्ट्रक्टर को निजी बनाने के लिए एक समाधान है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.