DarioSantarelli.Blog("UgiDotNet");

<sharing mode=”On” users=”*” />
posts - 176, comments - 144, trackbacks - 3

My Links

News


This is my personal blog. These postings are provided "AS IS" with no warranties, and confer no rights.

logo linkedIn logo Twitter logo FaceBook logo RSS logo Email

Logo DotNetMarche
Logo XPUG Marche



Tag Cloud

Archives

Post Categories

My English Blog

venerdì 22 ottobre 2010

Dictionary persistenti

In un mio progetto avevo bisogno di rendere persistenti dei Dictionary al fine di recuperarne lo stato al riavvio dell’applicazione. Poiché avevo bisogno di gestire un livello di astrazione rispetto allo storage utilizzato, ho anzitutto definito una classe astratta PersistentDictionary<TKey,TValue> derivando Dictionary<TKey,TValue> nel seguente modo:

public abstract class PersistentDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{  
    public abstract void Load();
   
public abstract void Save();   

}


Come è facile intuire, i metodi Load() e Save() servono per leggere/scrivere i dati del dictionary dallo/sullo storage.
Nella mia soluzione avevo la necessità di persistere su file system le coppie chiave/valore supportando diversi formati. Ho quindi creato un altro livello di astrazione per rappresentare i dictionary persistenti su file system.

public abstract class FileDictionary<TKey, TValue> : PersistentDictionary<TKey, TValue>

{

  public string FileName { get; private set; }

 

   public FileDictionary(string fileName)

  {

    if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentException("filename can't be null or empty");

    FileName = fileName;       

  }

}


Questo tipo di approccio mi ha permesso di lasciare la porta aperta a diverse personalizzazioni. Ad esempio, la seguente classe XmlFileDictionary<TKey,TValue> può essere utilizzata per serializzare/deserializzare in modo generico le coppie chiave/valore di qualunque tipo su un file XML sfruttando la classe XmlSerializer (scelta per rimanere retrocompatibile con il framework 2.0).

public class XmlFileDictionary<TKey, TValue> : FileDictionary<TKey, TValue>

{

  private XmlSerializer keySerializer;

  private XmlSerializer valueSerializer;

 

  public XmlFileDictionary(string fileName) : base(fileName)

  {

    keySerializer = new XmlSerializer(typeof(TKey));

    valueSerializer = new XmlSerializer(typeof(TValue));           

  }

 

  public override void Load()

  {

      if (File.Exists(this.FileName))

      {

        this.Clear();

 

         using (XmlReader reader = XmlReader.Create(this.FileName))

         {

           reader.ReadToFollowing("dictionary");

           if (!reader.IsEmptyElement)

           {

             reader.ReadToFollowing("item");

 

             while (reader.NodeType != 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();

                           

               reader.ReadEndElement();

 

               this.Add(key, value);

             }                       

           }

         }

      }

  }

 

  public override void Save()

  {          

     using (XmlWriter writer = XmlWriter.Create(this.FileName))

     {               

        writer.WriteStartDocument();

        writer.WriteStartElement("dictionary", string.Empty);

 

        foreach (TKey key in this.Keys)

        {

           writer.WriteStartElement("item");

 

           writer.WriteStartElement("key");

           keySerializer.Serialize(writer, key);

           writer.WriteEndElement();

 

           writer.WriteStartElement("value");

           valueSerializer.Serialize(writer, this[key]);

           writer.WriteEndElement();

 

           writer.WriteEndElement();

        }

 

        writer.WriteEndElement();               

     }

  }

}


Nel mio progetto inoltre ho dovuto gestire vari manifest per memorizzare degli indici di cache, sempre su file system. In ciascun file, sia le chiavi che i valori sono sempre di tipo stringa ed ogni coppia è memorizzata su una linea terminata da CRLF. Ho potuto quindi riutilizzare l’astrazione FileDictionary<TKey, TValue> sopra citata per definire una classe concreta che rappresenta un manifest file.

public class ManifestFile : FileDictionary<string, string>

{

  private const char DEFAULT_SEPARATOR = '|';

 

  private char _separator;

  private Encoding _encoding;

 

  public ManifestFile(string fileName) : this(fileName, DEFAULT_SEPARATOR, Encoding.Default) { }

  public ManifestFile(string fileName, char separator) : this(fileName, separator, Encoding.Default) { }

  public ManifestFile(string fileName, char separator, Encoding encoding) : base(fileName)

  {

    if (encoding == null) throw new ArgumentNullException("encoding can't be null");

    _separator = separator;

    _encoding = encoding;

  }

 

  public override void Load()

  {

    if (File.Exists(this.FileName))

    {

      this.Clear();

      string[] lines = File.ReadAllLines(this.FileName, _encoding);

      foreach (string line in lines)

      {

        string[] parts = line.Split(new char[] { _separator }, StringSplitOptions.RemoveEmptyEntries);

        this.Add(parts[0], parts[1]);

      }

    }

  }

 

  public override void Save()

  {

    if (this.Count > 0)

    {

      List<string> lines = new List<string>();

      foreach (string key in this.Keys) lines.Add(key + _separator + this[key]);

      File.WriteAllLines(this.FileName, lines.ToArray(), _encoding);

    }

    else File.WriteAllText(this.FileName, string.Empty, _encoding);

  }

}


Osservazioni e consigli sono ovviamente ben accetti!!! :)

Tag di Technorati: ,

posted @ venerdì 22 ottobre 2010 23.37 | Feedback (0) | Filed Under [ .NET ]

Powered by: