प्रकार निर्दिष्ट करने के लिए XmlInclude या SoapInclude विशेषता का उपयोग करें, जो कि सांख्यिकीय रूप से ज्ञात नहीं हैं


97

.NET के साथ काम करते समय मुझे एक बहुत ही अजीब समस्या आई है XmlSerializer

निम्नलिखित उदाहरण कक्षाएं लें:

public class Order 
{
    public PaymentCollection Payments { get; set; }

    //everything else is serializable (including other collections of non-abstract types)
}

public class PaymentCollection : Collection<Payment>
{
}

public abstract class Payment 
{
    //abstract methods
}

public class BankPayment : Payment
{
    //method implementations
}

AFAIK, इसे हल करने के लिए तीन अलग-अलग विधियां हैं जो InvalidOperationExceptionकि व्युत्पन्न प्रकारों के बारे में नहीं जानने वाले धारावाहिककार के कारण होती हैं Payment

1. जोड़ने XmlIncludeके लिए Paymentवर्ग परिभाषा:

यह सभी वर्गों को बाहरी संदर्भ के रूप में शामिल किए जाने के कारण संभव नहीं है, जिस पर मेरा कोई नियंत्रण नहीं है।

2. XmlSerializerउदाहरण के निर्माण के दौरान व्युत्पन्न प्रकारों को पास करना

काम नहीं करता है।

3. XmlAttributeOverridesसंपत्ति के डिफ़ॉल्ट क्रमांकन को ओवरराइड करने के लिए लक्ष्य संपत्ति के लिए परिभाषित करना (जैसा कि इस एसओ पोस्ट में बताया गया है )

इसके अलावा काम नहीं करता है ( XmlAttributeOverridesआरंभीकरण इस प्रकार है)।

Type bankPayment = typeof(BankPayment);

XmlAttributes attributes = new XmlAttributes();
attributes.XmlElements.Add(new XmlElementAttribute(bankPayment.Name, bankPayment));

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Order), "Payments", attributes);

उपयुक्त XmlSerializerकंस्ट्रक्टर तब उपयोग किया जाएगा।

ध्यान दें: काम नहीं करता है मेरा मतलब है InvalidOperationException( BankPaymentउम्मीद नहीं की गई थी ... ) फेंक दिया है।

क्या कोई इस विषय पर कुछ प्रकाश डाल सकता है? कोई इस मुद्दे को कैसे आगे बढ़ाएगा?

जवाबों:


92

यह मेरे लिए काम किया:

[XmlInclude(typeof(BankPayment))]
[Serializable]
public abstract class Payment { }    

[Serializable]
public class BankPayment : Payment {} 

[Serializable]
public class Payments : List<Payment>{}

XmlSerializer serializer = new XmlSerializer(typeof(Payments), new Type[]{typeof(Payment)});

15
तो आधार प्रकार को इसके सभी कार्यान्वयनों को जानने की आवश्यकता है? यह एक बहुत अच्छा समाधान की तरह प्रतीत नहीं होता है। क्या कोई और रास्ता नहीं है?
अलेक्जेंडर स्टोलज़

2
XmlSerializable Object बनाने के दौरान नए प्रकार से गुजरने वाले सामान्य कार्यान्वयन के लिए @AlexanderStolz सबसे अच्छा समाधान है। जैसा कि उल्लेख किया गया है stackoverflow.com/a/2689660/698127
Aamol

39

बस समस्या हल हो गई। थोड़ी देर तक चारों ओर खुदाई करने के बाद, मुझे यह एसओ पद मिला, जो ठीक उसी स्थिति को कवर करता है। इसने मुझे सही रास्ते पर ला दिया।

मूल रूप से, यदि अतिरिक्त वर्ग को अतिरिक्त प्रकार के रूप में शामिल किया गया है, तोXmlSerializer डिफ़ॉल्ट नाम स्थान को जानने की आवश्यकता है । ऐसा होने का सटीक कारण अभी भी अज्ञात है लेकिन, अभी भी, क्रमबद्धता काम कर रही है।


2

मैं bizl से सहमत हूँ

[XmlInclude(typeof(ParentOfTheItem))]
[Serializable]
public abstract class WarningsType{ }

इसके अलावा, यदि आपको किसी वस्तु के लिए इस सम्मिलित वर्ग को लागू करने की आवश्यकता है तो आप ऐसा कर सकते हैं

[System.Xml.Serialization.XmlElementAttribute("Warnings", typeof(WarningsType))]
public object[] Items
{
    get
    {
        return this.itemsField;
    }
    set
    {
        this.itemsField = value;
    }
}

1

बस इसे बेस में करें, इस तरह किसी भी बच्चे को सीरियलाइज़ किया जा सकता है, कम कोड क्लीनर कोड।

public abstract class XmlBaseClass  
{
  public virtual string Serialize()
  {
    this.SerializeValidation();

    XmlSerializerNamespaces XmlNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
    XmlWriterSettings XmlSettings = new XmlWriterSettings
    {
      Indent = true,
      OmitXmlDeclaration = true
    };

    StringWriter StringWriter = new StringWriter();

    XmlSerializer Serializer = new XmlSerializer(this.GetType());
    XmlWriter XmlWriter = XmlWriter.Create(StringWriter, XmlSettings);
    Serializer.Serialize(XmlWriter, this, XmlNamespaces);
    StringWriter.Flush();
    StringWriter.Close();

    return StringWriter.ToString();

  }

  protected virtual void SerializeValidation() {}
}

[XmlRoot(ElementName = "MyRoot", Namespace = "MyNamespace")]
public class XmlChildClass : XmlBaseClass
{
  protected override void SerializeValidation()
  {
    //Add custom validation logic here or anything else you need to do
  }
}

इस तरह से आप किसी भी परिस्थिति में बच्चे की कक्षा में सीरीज़ को कॉल कर सकते हैं और फिर भी ऑब्जेक्ट सीरियलाइज़ करने से पहले आपको वह करने में सक्षम होना चाहिए जो आपको चाहिए।


0

इस आधार पर मैं XmlSerializerकक्षाओं को बदलने के बजाय I के निर्माता को बदलकर इसे हल करने में सक्षम था।

इसके बजाय कुछ इस तरह का उपयोग करने (अन्य उत्तरों में सुझाए गए):

[XmlInclude(typeof(Derived))]
public class Base {}

public class Derived : Base {}

public void Serialize()
{
    TextWriter writer = new StreamWriter(SchedulePath);
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>));
    xmlSerializer.Serialize(writer, data);
    writer.Close();
}

इसे मैने किया है:

public class Base {}

public class Derived : Base {}

public void Serialize()
{
    TextWriter writer = new StreamWriter(SchedulePath);
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>), new[] { typeof(Derived) });
    xmlSerializer.Serialize(writer, data);
    writer.Close();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.