->
.NET ile kod yazarken en çok kullandığım collection tiplerinden biri olan Dictionary Generic yapısıile de bizi bir çok casting işleminden kuratarıyor. Key olarak şu tipi, value olarak da şu tipi kullanacağız diyoruz ve key/value çiftlerini tiplerini de koruyarak tutabileceğimiz dört başımamur bir listemiz olmuş oluyor. Bir de bu Dictionary tipimizi XML olarak Serialize edebilsek tadından yenmeyecek ama nedendir bilinmez bunu yapamıyoruz. Yaparsak da şuna benzer bir Exception alıyoruz:
“The type System.Collections.Generic.Dictionary is not supported because it implements IDictionary.â€
İnternette bu işi yapabilecek bir şeyler araştırdım ve hatrısayılır sitede bu sorunun farklıfarklı çözümlerine rastladım. Bunlardan en çok Pete Welter’in çözümü hoşuma gitti. Bu çözümde Pete Welter, Dictionary generic tipini ve IXmlSerializable tipini implement eden yeni bir tip yaratmış. Dictionary’den dolayıyeni tipimiz Dictionary ile beraber gelen tüm özelliklere sahip, oh ne güzel. IXmlSerializable tipinin gerektirdiği metodlarıda implement ederek XML Serialization işlemi sırasında yeni tipimizin nasıl serialize edileceğini de bildirmiş sevgili Pete Welter. Sonuç olarak temiz ve çok rahat kullanılabilir yeni bir tip ortaya çıkmış. Kod şu şekilde:
[XmlRoot(“dictionary”)] public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable { #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); bool wasEmpty = reader.IsEmptyElement; reader.Read(); if (wasEmpty) return; while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { reader.ReadStartElement(“item”); reader.ReadStartElement(“key”); TKey key = (TKey)keySerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadStartElement(“value”); TValue value = (TValue)valueSerializer.Deserialize(reader); reader.ReadEndElement(); this.Add(key, value); reader.ReadEndElement(); reader.MoveToContent(); } reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); foreach (TKey key in this.Keys) { writer.WriteStartElement(“item”); writer.WriteStartElement(“key”); keySerializer.Serialize(writer, key); writer.WriteEndElement(); writer.WriteStartElement(“value”); TValue value = this[key]; valueSerializer.Serialize(writer, value); writer.WriteEndElement(); writer.WriteEndElement(); } } #endregion }
Dictionary nesnemiz için serialize edilebilen key ve value tipleri seçtiğimiz sürece SerializableDictionary tipimiz de serialize edilebilir. Key/value tipleri olarak string kullandığımız bir SerializableDictionary nesnesini serialize ettiğimizde şöyle bir çıktıya sahip oluyor:
<dictionary> <item> <key> <string>foo</string> </key> <value> <string>bar</string> </value> </item> </dictionary>
Buraya kadar her şey güzel, Dictionary yerine bu yeni tipi kullanarak varolan Dictionary yapılarımızıXML olarak da serialize edebiliriz artık. Ama bir şey içime sinmiyor hala, XML çıktısındaki etiketlerin isimlerini SerializableDictionary üzerinde hard-coded olarak yazıyoruz. Kökteki etiket ismini XmlRootAttribute’e farklıbir parametre göndererek veya SerializableDictionary tipini extend eden yeni bir tip tanımlayarak değiştirebiliriz. Ama hala alt seviyelerdeki item, key ve value şeklindeki etiket isimlerini hard-code etmek dışında bir seçeneğimiz görünmüyor. Eğer bu sınıfıtek tipteki bir Dictionary verimiz için kullanacaksak pek bir sorun yok ama farklıfarklıXML çıktılarınıbeklediğimiz generic bir çözüm için bu tipi kullanmayıplanlıyorsak bu etiket isimlerine müdahale etmenin daha generic bir yolunu bulmamız gerek (copy/paste yapmayıbir çözüm olarak aklımızdan bile geçirmiyoruz tabii ki). Bu amaçla SerializableDictionary tipini biraz değiştirerek şu kodu elde ettim:
public abstract class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable { protected abstract string itemName { get; } protected abstract string keyName { get; } protected abstract string valueName { get; } #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(XmlReader reader) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); bool wasEmpty = reader.IsEmptyElement; reader.Read(); if (wasEmpty) return; while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { reader.ReadStartElement(itemName); reader.ReadStartElement(keyName); TKey key = (TKey)keySerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadStartElement(valueName); TValue value = (TValue)valueSerializer.Deserialize(reader); reader.ReadEndElement(); this.Add(key, value); reader.ReadEndElement(); reader.MoveToContent(); } reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); foreach (TKey key in this.Keys) { writer.WriteStartElement(itemName); writer.WriteStartElement(keyName); keySerializer.Serialize(writer, key); writer.WriteEndElement(); writer.WriteStartElement(valueName); TValue value = this[key]; valueSerializer.Serialize(writer, value); writer.WriteEndElement(); writer.WriteEndElement(); } } #endregion }
Override edilmek üzere 3 tane abstract property ekleyerek hard-coded string değerlerinden kurtulmuş olduk. Tipimize abstract üyeler eklediğimiz için artık bu tipi direk olarak kullanılamaz hale getirdik ve bir abstract tipimiz oldu. Tipimizi kullanmak istediğimizde yamamız gereken kod artık şu şekilde olacak:
public class Fields : SerializableDictionary<string, string> { protected override string itemName { get { return “Field”; } } protected override string keyName { get { return “Name”; } } protected override string valueName { get { return “Value”; } } }
Burada az önce değiştirdiğimiz SerializableDictionary tipini extend ederek kullanacağımız yeni tipi yaratıyoruz. Bu aşmada Key/Value tiplerimizi ve XML çıktısında oluşacak etiketlerin isimlerini belirtiyoruz. Eğer kök XML etiketi için kullanılacak ismin tipimizin isminden farklıolmasınıistiyorsanız yeni tipin üzerinde XmlRootAttribute kullanarak bunu da belirtebilirsiniz. Bu tipimizi de artık şu şekilde kullanabiliriz:
// 2 kayıt içeren bir Dictionary oluşturalım // .NET 3.5/VS2008 ile gelen Collection Initializers özelliği // bu gibi durumlarda daha temiz/kısa kod yazmamıza yarıyor Fields fields = new Fields { { “foo”, “bar” }, { “hede”, “hödö”} }; // XML Serialize işlemi için gerekli altyapıyıoluşturalım StringBuilder sb = new StringBuilder(); // Burada da bir başka yenilik olan Object Initializer özelliğini // kullanarak nesneyi oluşturduğumuz satırda nesne üzerindeki // bazıözelliklere de ilk değerlerini verebiliyoruz XmlTextWriter xtw = new XmlTextWriter(new StringWriter(sb)) { Formatting = Formatting.Indented }; xtw.WriteRaw(“”); // Burada XML Serialize işlemi gerçekleşiyor XmlSerializer xs = new XmlSerializer(typeof(Fields)); xs.Serialize(xtw, fields); string xmlFields = sb.ToString(); Console.WriteLine(xmlFields); // Burada da daha önce serialize ettiğimiz nesneyi deserialize ederek // tekrar hafızda bir nesne haline çeviriyoruz Fields deserializedFields = xs.Deserialize(new StringReader(xmlFields)) as Fields;
Bu kodun çıktısıda şu şekilde:
<Fields> <Field> <Name> <string>foo</string> </Name> <Value> <string>bar</string> </Value> </Field> <Field> <Name> <string>hede</string> </Name> <Value> <string>hödö</string> </Value> </Field> </Fields>
SerializableDictionary tipini bir kere tanımlayarak projemiz içerisinde bunu baz alan farklıfarklıDictionary tiplerimizi oluşturabilir, bunların farklıfarklıXML çıktılarıolmasınısağlayabiliriz.
Powered by MightyAdsense
No tag for this post.
17 Temmuz 2008 Saat 15:17
Nice Blog. Good Look
5 Ağustos 2008 Saat 04:00
Good blog. Good luck.
7 Ağustos 2008 Saat 13:41
CIALIS® actua aumentando el flujosanguineo en el pene en presencia de estimulacion sexual. Su principioactivo - Tadalafilo - actua como inhibidor reversible selectivo de lafosfodiestererasa especifica de tipo5 (PDE5), manteniendo elevado eldel GMPc, y en consecuencia la ereccion. tadalafil 20mg