One time I had to make cache for user interface settings. Cache had to keep last setted values for combo boxes and grouping settings for DevExpress GridViews. We must to ensure, that cache will be extensible for next components (it depends on user requirements). My implementation was established on Dictionary which kept unique key for component and value. Value was List<GridColumnItem> for grid columns (this list contained mandatory information for particular columns). Value contained DictionarySetting object for DropDown lists. In the future I can create another kind of objects. How you can see.
Unhappiness is , that classes which implements IDictionary is impossible to serialise. I found good article to serializable Dictionary here . It is good way, how to do it, but it is a little bit complicated to serialize different types of values in the one Dictionary.
Finally I solved this problem by implementation of mine special collection. This collection is based on List<NameValueObject>. List is easy to serialize. Nested NameValueObject is an object which keeps string Key and object Value. It enables to simulate Dictionary for me. For serialization of different types of objects you must adjust metadata for Value property in List<NameValueObject>. That’s all !! Disadvantage of this solution is recompilation of collection however you want to serialise new types of objects.
And now implementation:
ISerialisableDictionary.cs
using
System;
using System.Collections.Generic;
using System.Text;
namespace XmlSerializerTest
{
/// <summary>
/// Defines serializable dictionary
/// </summary>
public interface ISerializableDictionary
{
/// <summary>
/// Gets or sets object from collection by index.
/// Throws an exception if index doesn’t exist.
/// </summary>
/// <param name=“index”></param>
/// <returns></returns>
object this[int index] { get; set; }
/// <summary>
/// Gets or sets object from collecton by key.
/// Throws an exception if index doesn’t exist.
/// </summary>
/// <param name=“key”></param>
/// <returns></returns>
object this[string key] { get; set; }
/// <summary>
/// Add value to collection. If element exists in the collection, it will throw exception.
/// </summary>
/// <param name=“key”></param>
/// <param name=“value”></param>
void Add(string key, object value);
/// <summary>
/// Try to get value from collection if exist
/// </summary>
/// <param name=“key”></param>
/// <param name=“value”></param>
/// <returns>True if value exist elese returns false</returns>
bool TryGetValue(string key, out object value);
/// <summary>
/// returns true if item with defined key exists in the collection
/// </summary>
/// <param name=“key”></param>
/// <returns></returns>
bool Contains(string key);
}
}
SerialisableDictionary.cs
using
System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace XmlSerializerTest
{
/// <summary>
/// Simulation of Name value collection to list, which is serialisable.
/// </summary>
[XmlRoot("SerializableDictionary")]
[Serializable]
public class SerializableDictionary : ISerializableDictionary
{
private List<NameValueObject> list = new List<NameValueObject>();
/// <summary>
/// Serialize collecton
/// </summary>
/// <returns></returns>
public string Serialize()
{
StringBuilder stringBuilder = new StringBuilder();
XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary));
TextWriter writer = new StringWriter(stringBuilder);
serializer.Serialize(writer, this);
XmlDocument document = new XmlDocument();
document.LoadXml(stringBuilder.ToString());
return document.DocumentElement.OuterXml;
}
/// <summary>
/// Deserialise collection
/// </summary>
/// <param name=“xml”></param>
/// <returns></returns>
public static SerializableDictionary Deserialize(string xml)
{
SerializableDictionary serializableDictionary = null;
XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary));
TextReader reader = new StringReader(xml);
serializableDictionary = (serializer.Deserialize(reader) as SerializableDictionary);
return serializableDictionary;
}
public List<NameValueObject> List
{
get { return list; }
}
#region
ISerializableDictionary Members
public object this[int index]
{
get
{
if (list.Count > index)
return list[index].Value;
throw new IndexOutOfRangeException(string.Format(“{0} contains just {1} elements.”,this,this.list.Count));
}
set
{
if (list.Count > index)
list[index].Value = value;
throw new IndexOutOfRangeException(string.Format(“{0} contains just {1} elements.”, this, this.list.Count));
}
}
public object this[string key]
{
get
{
int index = GetIndexByKey(key);
if (index >= 0)
return list[index].Value;
throw new IndexOutOfRangeException(string.Format(“{0} doesn’t defined for {1} key.”, this, key));
}
set
{
int index = GetIndexByKey(key);
if (index >= 0)
list[index].Value = value;
throw new IndexOutOfRangeException(string.Format(“{0} doesn’t defined for {1} key.”, this, key));
}
}
public void Add(string key, object value)
{
if (!this.Contains(key))
list.Add(new NameValueObject(key, value));
else
throw new Exception(string.Format(“Value for key {0} exists in the collection”, key));
}
public bool TryGetValue(string key, out object value)
{
bool b = this.Contains(key);
if (b)
value = this[key];
else
value = null;
return b;
}
public bool Contains(string key)
{
return this.GetIndexByKey(key) == -1 ? false : true;
}
private int GetIndexByKey(string key)
{
return list.FindIndex(delegate(NameValueObject nameValueObject) { return nameValueObject.Key == key; });
}
#endregion
#region
NameValueObject
/// <summary>
/// Name value nested class simulates dictionary in the list
/// </summary>
[Serializable]
[XmlRoot("NameValueObject")]
public class NameValueObject
{
private string key;
private object value;
public NameValueObject(string key, object value)
{
this.value = value;
this.key = key;
}
//Each serializable object must contain implicit constructor
public NameValueObject(){}
public string Key
{
get { return key; }
set { key = value; }
}
/// <summary>
/// !!!!!!!!!!!!!!!!
/// If you will create new kind of object, that contains value,
/// than YOU MUST UPDATE THIS METADATA!!!!!
/// and nothing else !!!!!!!!!!!!!!!!!
/// </summary>
[XmlElementAttribute("ArrayOfAaa", typeof(List<Aaa>))]
[XmlElementAttribute("ArrayOfBbb", typeof(List<Bbb>))]
public object Value
{
get { return value; }
set { this.value = value; }
}
}
#endregion
}
}
Program.cs
namespace
XmlSerializerTest
{
#region neisted classes
[Serializable]
public class Aaa
{
private int _aaa;
private int _bbb;
public Aaa(int aaa, int bbb)
{
this._aaa = aaa; this._bbb = bbb;
}
public Aaa(){}
public int Aaaa
{
get{ return _aaa; }
set {_aaa = value;}
}
public int Bbbb
{
get {return _bbb;}
set {_bbb = value;}
}
}
[Serializable]
public class Bbb
{
private string _aaa;
private int _bbb;
public Bbb(string aaa, int bbb)
{ this._aaa = aaa; this._bbb = bbb; }
public Bbb(){}
public string Aaaa
{
get {return _aaa;}
set {_aaa = value;}
}
public int Bbbb
{
get{return _bbb;}
set{_bbb = value;}
}
}
#endregion
public class Program
{
public static void Main()
{
SerializableDictionary serializableDictionary = new SerializableDictionary();
List<Aaa> list = new List<Aaa>();
List<Bbb> list11 = new List<Bbb>();
list.Add(new Aaa(5, 69));
list.Add(new Aaa(5, 70));
list.Add(new Aaa(5, 71));
list11.Add(new Bbb(“ahooj”, 69));
list11.Add(new Bbb(“jak se mas”, 667));
serializableDictionary.Add(“list”, list);
serializableDictionary.Add(“list141″, list11);
string aaa = serializableDictionary.Serialize();
SerializableDictionary dict2 = SerializableDictionary.Deserialize(aaa);
}
}
}
Output
<SerializableDictionary xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<List>
<NameValueObject>
<Key>list</Key>
<ArrayOfAaa>
<Aaa>
<Aaaa>5</Aaaa>
<Bbbb>69</Bbbb>
</Aaa>
<Aaa>
<Aaaa>5</Aaaa>
<Bbbb>70</Bbbb>
</Aaa>
<Aaa>
<Aaaa>5</Aaaa>
<Bbbb>71</Bbbb>
</Aaa>
</ArrayOfAaa>
</NameValueObject>
<NameValueObject>
<Key>list141</Key>
<ArrayOfBbb>
<Bbb>
<Aaaa>ahooj</Aaaa>
<Bbbb>69</Bbbb>
</Bbb>
<Bbb>
<Aaaa>jak se mas</Aaaa>
<Bbbb>667</Bbbb>
</Bbb>
</ArrayOfBbb>
</NameValueObject>
</List>
</SerializableDictionary>
Links