2010-09-13 21 views
12

मैं एक सूची (टी) जारी रखने के लिए XmlSerializer का उपयोग करने का प्रयास कर रहा हूं जहां टी एक इंटरफ़ेस है। Serializer इंटरफेस पसंद नहीं है। मैं उत्सुक हूं कि XmlSerializer के साथ आसानी से विषम वस्तुओं की एक सूची क्रमबद्ध करने का एक आसान तरीका है। यहां मैं क्या कर रहा हूं:XmlSerializer इंटरफ़ेस की जेनेरिक सूची क्रमबद्ध करें

public interface IAnimal 
    { 
     int Age(); 
    } 
    public class Dog : IAnimal 
    { 
     public int Age() 
     { 
      return 1; 
     } 
    } 
    public class Cat : IAnimal 
    { 
     public int Age() 
     { 
      return 1; 
     } 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     var animals = new List<IAnimal> 
     { 
      new Dog(), 
      new Cat() 
     }; 

     var x = new XmlSerializer(animals.GetType()); 
     var b = new StringBuilder(); 
     var w = XmlTextWriter.Create(b, new XmlWriterSettings { NewLineChars = "\r\n", Indent = true }); 
     //FAIL - cannot serialize interface. Does easy way to do this exist? 
     x.Serialize(w, animals); 
     var s = b.ToString();  
    } 
+0

हो सकता है कि इस विषय में आपकी मदद http: // stackoverflow।कॉम/प्रश्न/10225174/उपयोग-डेटाकॉन्ट्राक्सेरियलाइज़र-और-डेटाप्रिएंटप्रोवाइडर-टू-सीरियलाइज-एंड-एन्क्रिप्शन – saramgsilva

उत्तर

3

क्या आपको XmlSerializer का उपयोग करना है? यह XmlSerializer के साथ एक ज्ञात मुद्दा है।

आप एक धारा को बचाने के लिए BinaryFormatter का उपयोग कर सकते हैं:

BinaryFormatter bf = new BinaryFormatter(); 
MemoryStream ms = new MemoryStream(); 
bf.Serialize(ms, animals); 

अन्य विकल्प WCF के DataContractSerializer का उपयोग करें और KnownType विशेषता का उपयोग प्रकार प्रदान करना है।

+0

मैं यह उल्लेख करना भूल गया कि इसकी टेक्स्ट होना आवश्यक है, इसलिए यदि आवश्यक हो तो मैं मैन्युअल रूप से संपादित कर सकता हूं, इसलिए बाइनरी काम नहीं करती है। DataContractSerializer अच्छा लग रहा है, लेकिन मैंने चारों ओर देखा और मिश्रित प्रकार की सूची को क्रमबद्ध करने का एक उदाहरण नहीं देखा। धन्यवाद! – Steve

13

आप XmlSerializer का भी उपयोग कर सकते हैं, लेकिन आपको ऑब्जेक्ट ग्राफ़ में दिखाई देने वाले सभी संभावित प्रकारों को शामिल करने की आवश्यकता है, जो एक्स्टेंसिबिलिटी को सीमित करते हैं और रखरखाव को कम करते हैं। जब XmlSerializer, उल्लिखित here (MSDN) के सभी का उपयोग कर

var x = new XmlSerializer(animals.GetType(), new Type[] { typeof(Cat), typeof(Dog) }); 

इसके अलावा, वहाँ टिप्पणी के कई मुद्दे हैं - उदाहरण के लिए शीर्षक 'डायनामिक रूप से जेनरेट विधानसभाओं' के तहत देखो: आप XmlSerializer के निर्माता की एक अधिभार का उपयोग करके यह कर सकते हैं ।

+0

मैंने कोशिश की लेकिन XmlSerializer अभी भी असफल रहा क्योंकि 'इंटरफ़ेस को क्रमबद्ध नहीं किया जा सकता'। मैं XmlSerializer के लिए इस सीटीओ को नहीं जानता था, धन्यवाद कुछ नया, धन्यवाद। – Steve

+5

@ स्टेव, मैं पशु नामक एक अमूर्त वर्ग बनाने की सिफारिश करता हूं जो IAimal को लागू करता है। इसके बाद आप सूची को क्रमबद्ध करने में सक्षम होंगे (माना जाता है कि आप XmlSerializer कन्स्ट्रक्टर को संशोधित करते हैं और बिल्ली और कुत्ते को आईएनिमल के बजाय अमूर्त वर्ग का उत्तराधिकारी भी मिलता है। Var animals = new list (); बदलने की आवश्यकता नहीं है। –

+1

@J मिशेल , इसके लिए बहुत बहुत धन्यवाद! मुझे एक ही समस्या थी ... – Ethenyl

7

XmlSerializer इंटरफ़ेस को संभाल नहीं सकता है क्योंकि यह नहीं जानता कि deserialising के दौरान किस प्रकार के निर्माण करना है। इसके आस-पास पहुंचने के लिए आपको IXmlSerializable इंटरफ़ेस को लागू करके स्वयं को क्रमबद्ध करने के उस भाग को संभालने की आवश्यकता है। यह आपको इस प्रकार को रिकॉर्ड करने की अनुमति देता है ताकि आप इसे फिर से बना सकें (deserialise)।

नीचे दिए गए ListOfIAnimal वर्ग से पता चलता है कि आवश्यक इंटरफ़ेस को लागू करने के लिए मैंने जेनेरिक सूची List<IAnimal> को विरासत में कैसे बढ़ाया और बढ़ाया। मैंने आपके पुराने वर्गों को प्रत्येक के लिए एक अतिरिक्त गैर-इंटरफ़ेस फ़ील्ड जोड़ दिया ताकि मैं देख सकूं कि कंक्रीट कक्षाएं क्रमबद्ध और व्यवस्थित हो रही हैं।

आपके कोड की तुलना में मैं List<IAnimal> के स्थान पर केवल नए प्रकार ListOfIAnimal का उपयोग कर रहा हूं, अन्य परिवर्तन केवल थोड़ा सा रिफैक्टरिंग हैं।

इसका पूरा कोड, बस इसे अपनी स्वयं की .cs फ़ाइल में कॉपी करें, इसके माध्यम से चरणबद्ध करने के लिए पहले फ़ंक्शन को कॉल करें।

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Text; 
using System.Xml; 
using System.Xml.Serialization; 

namespace Serialiser 
{ 
    static class SerialiseInterface 
    { 
     public static void SerialiseAnimals() 
     { 
      String finalXml; 

      // Serialize 
      { 
       var animals = new ListOfIAnimal{ 
        new Dog() { Age = 5, Teeth = 30 }, 
        new Cat() { Age = 6, Paws = 4 } 
       }; 

       var xmlSerializer = new XmlSerializer(animals.GetType()); 
       var stringBuilder = new StringBuilder(); 
       var xmlTextWriter = XmlTextWriter.Create(stringBuilder, new XmlWriterSettings { NewLineChars = "\r\n", Indent = true }); 
       xmlSerializer.Serialize(xmlTextWriter, animals); 
       finalXml = stringBuilder.ToString(); 
      } 

      // Deserialise 
      { 
       var xmlSerializer = new XmlSerializer(typeof(ListOfIAnimal)); 
       var xmlReader = XmlReader.Create(new StringReader(finalXml)); 
       ListOfIAnimal animals = (ListOfIAnimal)xmlSerializer.Deserialize(xmlReader); 
      } 
     } 
    } 

    public class ListOfIAnimal : List<IAnimal>, IXmlSerializable 
    { 
     public ListOfIAnimal() : base() { } 

     #region IXmlSerializable 
     public System.Xml.Schema.XmlSchema GetSchema() { return null; } 

     public void ReadXml(XmlReader reader) 
     { 
      reader.ReadStartElement("ListOfIAnimal"); 
      while (reader.IsStartElement("IAnimal")) 
      { 
       Type type = Type.GetType(reader.GetAttribute("AssemblyQualifiedName")); 
       XmlSerializer serial = new XmlSerializer(type); 

       reader.ReadStartElement("IAnimal"); 
       this.Add((IAnimal)serial.Deserialize(reader)); 
       reader.ReadEndElement(); //IAnimal 
      } 
      reader.ReadEndElement(); //ListOfIAnimal 
     } 

     public void WriteXml(XmlWriter writer) 
     { 
      foreach (IAnimal animal in this) 
      { 
       writer.WriteStartElement("IAnimal"); 
       writer.WriteAttributeString("AssemblyQualifiedName", animal.GetType().AssemblyQualifiedName); 
       XmlSerializer xmlSerializer = new XmlSerializer(animal.GetType()); 
       xmlSerializer.Serialize(writer, animal); 
       writer.WriteEndElement(); 
      } 
     } 
     #endregion 
    } 

    public interface IAnimal { int Age { get; set; } } 
    public class Dog : IAnimal { public int Age { get; set;} public int Teeth { get; set;} } 
    public class Cat : IAnimal { public int Age { get; set;} public int Paws { get; set;} } 
} 

मैंने पाठक के लिए अभ्यास के रूप में deserialize छोड़ने के बारे में सोचा, लेकिन कोड इसके बिना बहुत उपयोगी नहीं होगा।

+0

क्या यह सामान्य रूप से ऐसा करने का कोई तरीका नहीं है? उदाहरण के लिए, यदि कुत्ते में आयु और बिल्ली सिर्फ int नहीं बल्कि टी के बजाय, ऐसा करने का कोई तरीका नहीं है? – user99999991

+1

@ user999999928 [xml-serialization-of-interface-property] के स्वीकृत उत्तर को देखें (http://stackoverflow.com/questions/1333864/xml- serialization-of-interface-property) – nawfal

+0

यह बहुत अच्छा है। मुझे बहुत मदद मिली। एक चीज़ को छोड़कर। इस कक्षा के सदस्य को एक संपूर्ण XML संरचना में जोड़ना समस्याएं पैदा करेगा। 'ReadXML' विधि के भीतर आप shou ld एक 'if (reader.IsStartElement (" IAnimal ") 'को लूप से पहले जोड़ें और इसे' पाठक के बाद समाप्त करें। ReadEndElement();' line। अन्यथा आपका सीरियलाइजेशन पूरे एक्सएमएल सीरिएलाइज़र समाप्त होने से पहले समाप्त हो जाएगा – blackWorX

0

आसान तरीका है आपकी धारा पर [सीरियलज़ेबल()] सजावट जोड़ने और अपनी सूची को सूची में बदलें और देखें कि यह काम करता है या नहीं।

यदि आप इंटरफेस का उपयोग करते हैं तो वेबटर्नर का उत्तर देखें।

3

आप ExtendedXmlSerializer का उपयोग कर सकते हैं।

var serializer = new ExtendedXmlSerializer(); 
var xml = serializer.Serialize(animals); 

आपका एक्सएमएल दिखेगा की तरह:

<?xml version="1.0" encoding="utf-8"?> 
<ArrayOfIAnimal> 
    <Dog type="Model.Dog" /> 
    <Cat type="Model.Cat" /> 
</ArrayOfIAnimal> 
संबंधित मुद्दे