Sorun çözüldü!
Tamam, sonunda oraya geldim (kuşkusuz buradan çok yardım alarak !).
Öyleyse özetleyin:
Hedefler:
- Bakım baş ağrısından dolayı XmlInclude rotasına girmek istemedim .
- Bir çözüm bulunduğunda, diğer uygulamalarda uygulanmasının hızlı olmasını istedim.
- Özet türlerinin koleksiyonları ve ayrıca bireysel soyut özellikler kullanılabilir.
- Somut derslerde "özel" şeyler yapmak zorunda kalmayı gerçekten istemedim.
Belirlenen Sorunlar / Dikkat Edilmesi Gereken Noktalar:
- XmlSerializer oldukça güzel bir yansıtma yapar, ancak soyut türler söz konusu olduğunda çok sınırlıdır (yani alt sınıflarla değil, yalnızca soyut türün örnekleriyle çalışacaktır).
- Xml öznitelik çözümleyicileri, XmlSerializer'ın bulduğu özellikleri nasıl ele aldığını tanımlar. Fiziksel tür de belirtilebilir, ancak bu , sınıf ile serileştirici arasında sıkı bir bağlantı oluşturur (iyi değil).
- IXmlSerializable uygulayan bir sınıf oluşturarak kendi XmlSerializer'ımızı uygulayabiliriz .
Çözüm
Çalışacağınız soyut tür olarak genel türü belirttiğiniz genel bir sınıf oluşturdum. Bu, sınıfa soyut tür ile somut tür arasında "çevirme" yeteneği verir, çünkü dökümü sabit kodlayabiliriz (yani XmlSerializer'ın alabileceğinden daha fazla bilgi alabiliriz).
Daha sonra IXmlSerializable arabirimini uyguladım , bu oldukça basittir, ancak serileştirirken somut sınıfın türünü XML'e yazdığımızdan emin olmamız gerekir, böylece serileştirmeyi kaldırırken onu geri döndürebiliriz. Ayrıca, iki sınıfın büyük olasılıkla farklı olduğu meclislerin tamamen nitelendirilmesi gerektiğine dikkat etmek önemlidir . Elbette küçük bir tür kontrolü ve burada olması gereken şeyler var.
XmlSerializer yayınlayamadığından, bunu yapmak için kodu sağlamamız gerekir, böylece örtük operatör aşırı yüklenir (bunu yapabileceğinizi bile bilmiyordum!).
AbstractXmlSerializer için kod şudur:
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
}
}
Öyleyse, oradan, XmlSerializer'a varsayılan yerine serileştiricimizle çalışmasını nasıl söyleyebiliriz? Türümüzü Xml öznitelikleri türü özelliği içinde geçirmeliyiz, örneğin:
[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>();
}
}
Burada, bir koleksiyonumuz ve açığa çıkan tek bir özelliğimiz olduğunu görebilirsiniz ve tek yapmamız gereken, tür adındaki parametreyi Xml bildirimine eklemektir , kolay! : D
NOT: Bu kodu kullanırsanız, gerçekten duymaktan memnun olurum. Aynı zamanda topluluğa daha fazla insan çekmeye yardımcı olacaktır :)
Şimdi, ama hepsinin profesyonelleri ve eksileri olduğu için buradaki cevaplarla ne yapılacağından emin değil. Yararlı olduğunu düşündüğümleri modifiye edeceğim (olmayanlara gücenme) ve temsilciye sahip olduğumda bunu kapatacağım :)
İlginç bir sorun ve çözmek için eğlenceli! :)