C# - Persistindo uma coleção entre sessões da aplicação
Hoje vamos recordar como persistir dados de uma coleção entre sessões de uma aplicação na linguagem C#. |
Existem muitas maneiras de persistir dados em uma aplicação e isso vai depender do ambiente, do tipo da aplicação e do que você deseja e precisa executar.
Vamos supor que você tem uma coleção como ArrayList, List<T>, Hashtable ou Dictionary<T, U> no qual você está armazenando informações do aplicativo como dados de configurações, preferências do usuário, etc. e você precisa usar esta informação em outras partes da aplicação ou mesmo quando a aplicação for reiniciada.
Como persistir os dados das coleções de forma que quando a aplicação for encerrada os dados estejam preservados e prontos para serem usados na reinicialização da aplicação ?
Uma técnica simples e que pode ser usada é realizar a serialização dos dados.
Já ouviu falar em serialização ?
O que é serializar ? Como podemos fazer isto na plataforma .NET ?
De forma genérica a serialização é uma técnica usada para persistir objetos , ou seja : gravar objetos em disco , fazer a transmissão remota de objetos via rede , armazenar os objetos em um banco de dados e/ou arquivos (binários , xml, etc.)
Serializar nada mais é do que colocar os valores que o objeto está utilizando juntamente com suas propriedades de uma forma que fique em série (sequencial) . Fazendo isto estamos tornando o objeto Serializable, e, tornando um objeto Serializable, estamos atribuindo essa qualidade a ele, e dando privilégios para que o mesmo possa ser gravado em disco ou enviado por rede.
A serialização é o processo de armazenar um objeto , incluindo todos os atributos públicos e privados para um stream.
Se você faz a serialização naturalmente vai querer fazer o processo inverso - desserialização , que seria restaurar os atributos de um objeto gravado em um stream. (Este stream pode ser um arquivo binário , xml , etc.)
Nota: Tradução de stream - fluxo (no caso de dados) . Melhor deixar stream mesmo.
Assim, podemos usar o recurso Generics da linguagem C# e criar uma classe que faça a serialização e o processo inverso.
Abaixo temos um código bem simples que pode ser usado para serializar e desserializar objetos:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace CShp_PersisteData
{
public class Serializar
{
public static void ParaArquivo<T>(T obj, string arquivo)
{
try
{
using (FileStream fileStream = File.Create(arquivo))
{
BinaryFormatter binSerializer = new BinaryFormatter();
binSerializer.Serialize(fileStream, obj);
}
}
catch (System.Exception)
{
throw;
}
}
public static T DoArquivo<T>(string arquivo)
{
try
{
T obj = default(T);
using (FileStream fileStream = File.OpenRead(arquivo))
{
BinaryFormatter binSerializer = new BinaryFormatter();
obj = (T)binSerializer.Deserialize(fileStream);
}
return obj;
}
catch (System.Exception)
{
throw;
}
}
}
}
|
Neste código temos que:
O parâmetro arquivo refere-se ao nome do arquivo e o método ParaArquivo<T> aceita um objeto e tenta serializá-lo em um arquivo usando o método Serialize da classe BinaryFormat.
Por outro lado, o método DoArquivo<T> remove o objeto serializado do arquivo.
Abaixo temos um exemplo de uso desta classe onde serializamos e a seguir desserializamos os dados de um ArrayList e um HashTable :
using System;
using System.Collections;
namespace CShp_PersisteData
{
class Program
{
static void Main(string[] args)
{
ArrayList referencias = new ArrayList() { "macoratti@yahoo.com", "macoratti.net"};
Hashtable enderecos = new Hashtable();
enderecos.Add("Macoratti", "Rua Projetada 100");
enderecos.Add("JcmSoft", "Av. Lusitânia , 200");
foreach (object O in referencias)
Console.WriteLine(O.ToString());
Console.WriteLine("### Serializando dados ###");
Serializar.ParaArquivo<ArrayList>(referencias, "referencias.data");
Serializar.ParaArquivo<Hashtable>(enderecos, "enderecos.data");
ArrayList minhasReferencias = new ArrayList();
Hashtable meusEnderecos = new Hashtable();
minhasReferencias = Serializar.DoArquivo<ArrayList>("referencias.data");
Console.WriteLine("### Desserializando dados ###\n");
Console.WriteLine("Minhas Referências");
foreach (object O in minhasReferencias)
Console.WriteLine(O.ToString());
meusEnderecos = Serializar.DoArquivo<Hashtable>("enderecos.data");
Console.WriteLine("\nMeus Endereços"); foreach (DictionaryEntry endereco in meusEnderecos) Console.WriteLine($"{endereco.Key} - {endereco.Value}"); Console.ReadLine();
}
}
}
|
Abaixo o resultado obtido:
No exemplo estamos serializando os dados da coleção para o disco mas podemos também serializar e desserializar para um armazenamento remoto usando um MemoryStream() conforme a implementação abaixo:
public static byte[] ParaMemoria<T>(T obj)
{
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binSerializer = new BinaryFormatter();
binSerializer.Serialize(memStream, obj);
return memStream.ToArray();
}
}
public static T DaMemoria<T>(byte[] serializedObj)
{
T obj = default(T);
using (MemoryStream memStream = new MemoryStream(serializedObj))
{
BinaryFormatter binSerializer = new BinaryFormatter();
obj = (T)binSerializer.Deserialize(memStream);
}
return obj;
}
|
Você deve considerar a utilização deste recurso levando em considerações as novas versões que seu projeto poderá ter planejando uma estratégia para garantir que os tipos que você serializa não sejam alterados.
Pegue o projeto aqui: CShp_PersisteData.zip
"Porque a palavra de Deus é viva e
eficaz, e mais penetrante do que espada alguma de dois gumes, e penetra até à
divisão da alma e do espírito, e das juntas e medulas, e é apta para discernir
os pensamentos e intenções do coração."
Hebreus 4:12
Referências:
C# - Tasks x Threads. Qual a diferença
C# - Programação Assíncrona como : Asycn e Task
C# - O Struct Guid - Macoratti.net