दिलचस्प पोस्ट
चित्रों को डेटाबेस में कैसे सहेजें मैं कैसे जांचूं अगर एक सरणी में जावास्क्रिप्ट में एक वस्तु शामिल है? दिनों में दिन में जावा में कैसे जोड़ सकते हैं क्या (कार्यात्मक) प्रतिक्रियाशील प्रोग्रामिंग है? एक स्थिर std :: नक्शा <int, int> सी ++ में शुरू कर रहा है TINYTEXT, टेक्स्ट, MEDIUMTEXT और LONGTEXT अधिकतम संग्रहण आकार पायथन – एकाधिक सूचियों का अन्तराल? निर्धारित करें कि क्या दो दिनांक सीमा ओवरलैप है jquery ui संवाद: प्रारंभ करने से पहले संवाद पर तरीकों को कॉल नहीं कर सकता पायथन: defaultdict का डिफ़ॉल्ट दिशानिर्देश? जावा या वेनिला जावास्क्रिप्ट में डोम उत्परिवर्तन की घटना सीमा नीचे से तालिका पंक्ति <tr> जोड़ें तुलना करने के लिए परे का उपयोग करने के लिए विजुअल स्टूडियो को कॉन्फ़िगर कैसे करें वास्तव में प्रोग्रामिंग क्या है? सर्वर और क्लाइंट दोनों को अवरोधित किए बिना वास्तविक समय में सर्वर पर अपलोड की गई फ़ाइल का फ़ाइल आकार कैसे पढ़ा और गूंजता है?

एक्सएमएल सीरियललाइज़ेशन और इनहेराईटेड टाइप

मेरे पिछले प्रश्न के बाद से मैं अपना ऑब्जेक्ट मॉडल एक्सएमएल को सीरियलाइज़ करने के लिए काम कर रहा हूं। लेकिन मैं अब एक समस्या (चकित आश्चर्य!) में चला गया हूँ

मेरे पास समस्या यह है कि मेरे पास एक संग्रह है, जो एक सार बेस क्लास प्रकार का है, जो कंक्रीट व्युत्पन्न प्रकारों द्वारा आबादी है।

मैंने सोचा था कि इसमें शामिल सभी कक्षाओं में एक्सएमएल गुण जोड़ना ठीक होगा और सब कुछ पीच होगा। अफसोस की बात है, मामला नहीं है!

इसलिए मैंने Google पर कुछ खुदाई की है और अब मुझे समझ में आ रहा है कि यह काम क्यों नहीं कर रहा है। इसमें एक्सएमएल XmlSerializer वास्तव में कुछ चालाक प्रतिबिंब कर रहा है ताकि एक्सएमएल से / वस्तुओं को सीरियलाइज़ कर सकें, और इसकी वजह से अमूर्त प्रकार के आधार पर, यह यह नहीं समझ सकता कि यह किस बात से बात कर रहा है । ठीक।

मैं इस पृष्ठ को कोडप्रोजेक्ट पर आया था, ऐसा लगता है कि यह बहुत अच्छी तरह से मदद कर सकता है (फिर भी पढ़ने / पूरी तरह से उपभोग), लेकिन मैंने सोचा कि मैं इस समस्या को स्टैक ओवरफ्लो टेबल पर भी लाना चाहूंगा, यह देखने के लिए कि क्या आपके पास कोई साफ हैक्स / ट्रिक्स को प्राप्त करने के लिए और तेज / हल्के तरीके से संभव में चलने के लिए।

एक बात मुझे भी जोड़नी चाहिए कि मैं XmlInclude मार्ग नीचे नहीं जाना चाहता। इसके साथ बहुत अधिक युग्मन है, और सिस्टम के इस क्षेत्र में भारी विकास हो रहा है, इसलिए यह एक असली रखरखाव सिरदर्द होगा!

वेब के समाधान से एकत्रित समाधान "एक्सएमएल सीरियललाइज़ेशन और इनहेराईटेड टाइप"

समस्या सुलझ गयी!

ठीक है, इसलिए मैं अंत में वहाँ गया (बेशक यहाँ से बहुत मदद के साथ!)।

तो संक्षेप करें:

लक्ष्य:

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

नोट करने के लिए पहचाने जाने वाले मुद्दे / अंक:

  • XmlSerializer कुछ बहुत अच्छा प्रतिबिंब करता है, लेकिन यह बहुत ही सीमित है जब यह सार प्रकारों के लिए आता है (यानी यह केवल सार प्रकार के उदाहरणों के साथ ही काम करेगा, उप-वर्ग नहीं)।
  • एक्सएमएल विशेषता सजावटी परिभाषित करता है कि XmlSerializer उसके गुणों को कैसे खोजता है भौतिक प्रकार को भी निर्दिष्ट किया जा सकता है, लेकिन यह कक्षा और सीरियलइज़र (अच्छा नहीं) के बीच एक तंग युग्मन बनाता है।
  • IXmlSerializable लागू करता है जो एक वर्ग बनाकर हम अपने खुद के XmlSerializer लागू कर सकते हैं

समाधान

मैंने एक जेनेरिक वर्ग बनाया, जिसमें आप सामान्य प्रकार को सार प्रकार के रूप में निर्दिष्ट करते हैं जो आप के साथ काम करेंगे। इससे क्लास को अमूर्त प्रकार और ठोस प्रकार के बीच "अनुवाद" करने की क्षमता मिलती है क्योंकि हम कठोर कोड को कास्टिंग कर सकते हैं (यानी हम XmlSerializer से अधिक जानकारी प्राप्त कर सकते हैं)।

मैंने तब IXmlSerializable इंटरफ़ेस लागू किया, यह काफी सीधे आगे है, लेकिन जब serializing हमें यह सुनिश्चित करने की आवश्यकता है कि हम कंक्रीट वर्ग के प्रकार को एक्सएमएल में लिखते हैं, तो हम डी-सीरियललाइजिंग करते समय इसे वापस कर सकते हैं। यह भी नोट करना महत्वपूर्ण है कि इसे पूरी तरह से योग्य होना चाहिए क्योंकि विधानसभाएं जो कि दो कक्षाओं में हैं भिन्न होने की संभावना है। निश्चित रूप से एक छोटी सी प्रकार की जाँच और सामान है जो यहां होने की आवश्यकता है।

चूंकि XmlSerializer नहीं डाल सकता है, इसलिए हमें ऐसा करने के लिए कोड प्रदान करना होगा, इसलिए निहित ऑपरेटर तब ओवरलोड किया गया है (मैं कभी भी यह नहीं जानता था कि आप यह कर सकते हैं!)।

AbstractXmlSerializer के लिए कोड यह है:

 using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization; namespace Utility.Xml { public class AbstractXmlSerializer<AbstractType> : IXmlSerializable { // Override the Implicit Conversions Since the XmlSerializer // Casts to/from the required types implicitly. public static implicit operator AbstractType(AbstractXmlSerializer<AbstractType> o) { return o.Data; } public static implicit operator AbstractXmlSerializer<AbstractType>(AbstractType o) { return o == null ? null : new AbstractXmlSerializer<AbstractType>(o); } private AbstractType _data; /// <summary> /// [Concrete] Data to be stored/is stored as XML. /// </summary> public AbstractType Data { get { return _data; } set { _data = value; } } /// <summary> /// **DO NOT USE** This is only added to enable XML Serialization. /// </summary> /// <remarks>DO NOT USE THIS CONSTRUCTOR</remarks> public AbstractXmlSerializer() { // Default Ctor (Required for Xml Serialization - DO NOT USE) } /// <summary> /// Initialises the Serializer to work with the given data. /// </summary> /// <param name="data">Concrete Object of the AbstractType Specified.</param> public AbstractXmlSerializer(AbstractType data) { _data = data; } #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; // this is fine as schema is unknown. } public void ReadXml(System.Xml.XmlReader reader) { // Cast the Data back from the Abstract Type. string typeAttrib = reader.GetAttribute("type"); // Ensure the Type was Specified if (typeAttrib == null) throw new ArgumentNullException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name + "' because no 'type' attribute was specified in the XML."); Type type = Type.GetType(typeAttrib); // Check the Type is Found. if (type == null) throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name + "' because the type specified in the XML was not found."); // Check the Type is a Subclass of the AbstractType. if (!type.IsSubclassOf(typeof(AbstractType))) throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name + "' because the Type specified in the XML differs ('" + type.Name + "')."); // Read the Data, Deserializing based on the (now known) concrete type. reader.ReadStartElement(); this.Data = (AbstractType)new XmlSerializer(type).Deserialize(reader); reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { // Write the Type Name to the XML Element as an Attrib and Serialize Type type = _data.GetType(); // BugFix: Assembly must be FQN since Types can/are external to current. writer.WriteAttributeString("type", type.AssemblyQualifiedName); new XmlSerializer(type).Serialize(writer, _data); } #endregion } } 

तो, वहां से, हम डिफ़ॉल्ट के बजाय हमारे सीरियललाइज़र के साथ काम करने के लिए XmlSerializer को कैसे बता सकते हैं? उदाहरण के लिए हमें एक्सएमएल गुण प्रकार की संपत्ति के अंदर अपना प्रकार पास करना होगा:

 [XmlRoot("ClassWithAbstractCollection")] public class ClassWithAbstractCollection { private List<AbstractType> _list; [XmlArray("ListItems")] [XmlArrayItem("ListItem", Type = typeof(AbstractXmlSerializer<AbstractType>))] public List<AbstractType> List { get { return _list; } set { _list = value; } } private AbstractType _prop; [XmlElement("MyProperty", Type=typeof(AbstractXmlSerializer<AbstractType>))] public AbstractType MyProperty { get { return _prop; } set { _prop = value; } } public ClassWithAbstractCollection() { _list = new List<AbstractType>(); } } 

यहां आप देख सकते हैं, हमारे पास एक संग्रह है और एक एकल संपत्ति उजागर हो रही है, और हमें जो कुछ करना है, एक्सएमएल घोषणा करने के लिए नामित पैरामीटर जोड़ना आसान है! : डी

नोट: यदि आप इस कोड का उपयोग करते हैं, तो मैं वास्तव में चिल्लाऊंगी। इससे समुदाय में अधिक लोगों को चलाने में भी मदद मिलेगी 🙂

अब, लेकिन यहां उत्तर के साथ क्या करना है, इस बारे में अनिश्चित है क्योंकि सभी के पास उनके समर्थक और चुनाव है। मैं उन लोगों को बढ़ाऊंगा जो मुझे लगता है कि वे उपयोगी थे (उन लोगों के लिए कोई गुनाह नहीं था) और मेरे पास एक बार फिर प्रतिनिधि बंद हो गया है 🙂

दिलचस्प समस्या और हल करने के लिए मज़ेदार! 🙂

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

एक्स्ट्रा टाइप्स परम के साथ एक्सएमएल सर्जरीकार कन्स्ट्रक्टर

संपादित करें: मैं जोड़ूंगा कि इस दृष्टिकोण का उपयोग XmlInclude attributes आदि पर लाभ होता है ताकि आप रनटाइम पर अपने संभावित कंक्रीट प्रकार की एक सूची को खोज और संसाधित करने का एक तरीका तैयार कर सकें और इन्हें सामान में डाल सकें।

गंभीरता से, POCOs का एक एक्स्टेंसिबल ढांचा कभी-कभी XML पर कभी भी सीरियल नहीं करेगा। मैं यह कहता हूं क्योंकि मैं गारंटी कर सकता हूं कि किसी के साथ आ जाएगा, अपनी कक्षा का विस्तार करें, और इसे दबाएं।

अपने ऑब्जेक्ट ग्राफ़ को क्रमबद्ध करने के लिए आपको XAML का उपयोग करना चाहिए। यह ऐसा करने के लिए डिज़ाइन किया गया है, जबकि एक्सएमएल सीरियलाइजेशन नहीं है।

Xaml धारावाहिक और deserializer समस्या के बिना जेनेरिक को संभालता है, साथ ही आधार वर्गों और इंटरफेस का संग्रह (जब तक संग्रह स्वयं IList या IDictionary को लागू करता है)। कुछ चेतावनियां हैं, जैसे DesignerSerializationAttribute सेरिअलाइज़ेशन एट्रिब्यूट के साथ अपनी पढ़ी गई संग्रह संपत्तियों को चिह्नित करने पर, लेकिन इन कोने के मामलों को संभाल करने के लिए आपका कोड दोबारा शुरू करना मुश्किल नहीं है।

बस इस पर एक त्वरित अद्यतन, मैं भूल नहीं है!

बस कुछ और शोध कर रहे हैं, ऐसा लगता है कि मैं विजेता हूं, बस कोड को सॉर्ट करने की ज़रूरत है

अब तक, मेरे पास निम्न हैं:

  • XmlSeralizer मूल रूप से एक वर्ग है जो वर्गों पर कुछ निफ्टी प्रतिबिंब करता है जो यह सीरियललाज कर रहा है। यह उन गुणों को निर्धारित करता है जो प्रकार के आधार पर क्रमबद्ध होते हैं।
  • समस्या यह होती है कि एक प्रकार की बेमेल होने के कारण, यह बेसटाइप की अपेक्षा कर रहा है, लेकिन वास्तव में DeriveType प्राप्त करता है .. जब आपको लगता है कि यह बहुरूपता से व्यवहार करेगा, तब से यह पूरी अतिरिक्त भार नहीं करेगा प्रतिबिंब और प्रकार जांच, जो इसे करने के लिए तैयार नहीं है

यह व्यवहार धारावाहिककर्ता के लिए जाने-बीच के रूप में कार्य करने के लिए एक प्रॉक्सी वर्ग बनाकर अधिरोहित होने के लिए (कोड लंबित) प्रतीत होता है यह मूल रूप से व्युत्पन्न वर्ग के प्रकार को निर्धारित करेगा और फिर सामान्य रूप से यह क्रमबद्ध करेगा। यह प्रॉक्सी वर्ग तब उस XML फ़ीड को मुख्य सीरियलइज़र को वापस फ़ीड करेगा ..

इस जगह को देखो! ^ _ ^

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

 type.AssemblyQualifiedName 

जो दिखता है

 TopNamespace.SubNameSpace.ContainingClass+NestedClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089 

जिसमें आपके विधानसभा विशेषताओं और संस्करण शामिल हैं …

अब अगर आप अपना विधानसभा संस्करण बदलने की कोशिश करते हैं, या आप इसे हस्ताक्षर करने का निर्णय लेते हैं, तो यह deserialization काम नहीं कर रहा है …

मैंने इसके जैसा काम किया है मैं सामान्य रूप से क्या करता हूं यह सुनिश्चित कर लें कि सभी XML सीरियलाइजेशन विशेषताओं कंक्रीट वर्ग में हैं, और उस क्लास के गुणों को आधार क्लास (जहां आवश्यक हो) के माध्यम से प्राप्त करने के लिए जानकारी प्राप्त करने के लिए सुनिश्चित करें कि जब सीरियलइज़र कॉल करता है उन गुण यह थोड़ा और कोडन काम है, लेकिन यह सीरियलइज़र को सही काम करने के लिए मजबूर करने के प्रयास से बेहतर काम करता है

संकेतन का उपयोग करते हुए भी बेहतर:

 [XmlRoot] public class MyClass { public abstract class MyAbstract {} public class MyInherited : MyAbstract {} [XmlArray(), XmlArrayItem(typeof(MyInherited))] public MyAbstract[] Items {get; set; } }