समस्या सुलझ गयी!
ठीक है, इसलिए मैं अंत में वहां पहुंच गया ( यहाँ से बहुत मदद के साथ ( !)
इसलिए संक्षिप्त करें:
लक्ष्य:
- मैं मुख्य सिरदर्द के कारण XmlInclude मार्ग से नीचे नहीं जाना चाहता था ।
- एक बार एक समाधान मिल गया था, मैं चाहता था कि यह अन्य अनुप्रयोगों में लागू करने के लिए जल्दी हो।
- सार प्रकार के संग्रह का उपयोग किया जा सकता है, साथ ही साथ व्यक्तिगत सार गुण भी।
- मैं वास्तव में ठोस वर्गों में "विशेष" चीजें करने से परेशान नहीं होना चाहता था।
नोट करने के लिए पहचाने गए मुद्दे / अंक:
- XmlSerializer कुछ बहुत अच्छा परावर्तन करता है, लेकिन यह बहुत सीमित है जब यह अमूर्त प्रकारों की बात आती है (अर्थात यह केवल अमूर्त प्रकार के उदाहरणों के साथ काम करेगा, न कि उपवर्ग)।
- Xml विशेषता डेकोरेटर्स यह परिभाषित करते हैं कि XmlSerializer कैसे अपने गुणों का पता लगाता है। भौतिक प्रकार भी निर्दिष्ट किया जा सकता है, लेकिन यह वर्ग और धारावाहिक (अच्छे नहीं) के बीच एक तंग युग्मन बनाता है ।
- हम अपने खुद के XmlSerializer को एक वर्ग बनाकर कार्यान्वित कर सकते हैं जो IXmlSerializable को लागू करता है ।
समाधान
मैंने एक जेनेरिक क्लास बनाया, जिसमें आप जेनेरिक प्रकार को उस अमूर्त प्रकार के रूप में निर्दिष्ट करते हैं जिसके साथ आप काम कर रहे होंगे। यह वर्ग को अमूर्त प्रकार और ठोस प्रकार के बीच "अनुवाद" करने की क्षमता प्रदान करता है क्योंकि हम कास्टिंग को हार्ड-कोड कर सकते हैं (यानी हम एक्सएमएलसियर की तुलना में अधिक जानकारी प्राप्त कर सकते हैं)।
मैंने तब IXmlSerializable इंटरफ़ेस लागू किया , यह बहुत ही सीधे आगे है, लेकिन जब क्रमबद्ध करने के लिए हमें यह सुनिश्चित करने की आवश्यकता है कि हम XML को ठोस वर्ग का प्रकार लिखें, तो हम इसे डी-सीरियलिंग करते समय वापस ला सकते हैं। यह भी ध्यान रखना महत्वपूर्ण है कि यह पूरी तरह से योग्य होना चाहिए क्योंकि असेंबली दोनों वर्गों के अलग-अलग होने की संभावना है। बेशक थोड़ा प्रकार की जाँच और सामान है जो यहाँ होने की आवश्यकता है।
चूंकि XmlSerializer कास्ट नहीं कर सकता है, हमें ऐसा करने के लिए कोड प्रदान करने की आवश्यकता है, इसलिए निहित ऑपरेटर को फिर से अधिभारित किया गया है (मुझे कभी भी नहीं पता था कि आप ऐसा कर सकते हैं!)।
इस AbstractXmlSerializer के लिए कोड है:
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace Utility.Xml
{
public class AbstractXmlSerializer<AbstractType> : IXmlSerializable
{
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;
public AbstractType Data
{
get { return _data; }
set { _data = value; }
}
public AbstractXmlSerializer()
{
}
public AbstractXmlSerializer(AbstractType data)
{
_data = data;
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
string typeAttrib = reader.GetAttribute("type");
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);
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.");
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 + "').");
reader.ReadStartElement();
this.Data = (AbstractType)new
XmlSerializer(type).Deserialize(reader);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
Type type = _data.GetType();
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
new XmlSerializer(type).Serialize(writer, _data);
}
#endregion
}
}
तो, वहाँ से, हम कैसे XmlSerializer को डिफ़ॉल्ट के बजाय हमारे धारावाहिक के साथ काम करने के लिए कहते हैं? हमें अपने प्रकार को Xml विशेषताओं प्रकार की संपत्ति में पास करना चाहिए, उदाहरण के लिए:
[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>();
}
}
यहां आप देख सकते हैं, हमारे पास एक संग्रह और एक एकल संपत्ति उजागर हो रही है, और हमें बस इतना करना है कि नाम टाइप पैरामीटर को Xml घोषणा में जोड़ दें , आसान! : डी
नोट: यदि आप इस कोड का उपयोग करते हैं, तो मैं वास्तव में एक चिल्लाओ की सराहना करूंगा। यह समुदाय में अधिक लोगों को ड्राइव करने में भी मदद करेगा :)
अब, लेकिन अनिश्चित के रूप में यहाँ क्या जवाब के साथ के बाद से वे सब उनके समर्थक है और चुनाव है। मैं उन लोगों को उखाड़ फेंकूंगा जो मुझे लगता है कि उपयोगी थे (जो उन लोगों के लिए कोई अपराध नहीं थे) और इस प्रतिनिधि को एक बार बंद करने के बाद मैं प्रतिनिधि हूं :)
दिलचस्प समस्या और हल करने के लिए अच्छा मज़ा! :)