Poznáváme C# a Microsoft.NET 40. díl – serializace

Dnešní díl se začneme věnovat serializaci. Vysvětlíme si co tento pojem znamená, jak vytvářet serializovatelné typy a jakými způsoby tyto typy serializovat.

Co je to serializace?

Mnoho instancí, které při svém programování používáme mají celkem krátký „život“. Jsou nějakou cestou (konstruktorem, skrze reflexi, tovární metodou…) vytvořeny, po té jsou nějakým způsobem použity a pak když nejsou potřeba (neexistuje na ně jakákoliv reference)  jsou při úklidu (Garbage collection) Garbage collectorem odstraněny z paměti. Ovšem, ne všechny instance jsou používány takto krátce a některé instance nesoucí potřebná data potřebujeme zachovat na delší dobu. To dokážeme zařídit tak, že onu instanci uložíme do nějakého perzistentního úložiště (relační databáze, soubor..). Takovémuto uložení instance do perzistentního úložiště se říká Serializace.  V podstatě jde o to, že instance je převedena na Stream, tím pádem může být, jak již bylo řečeno, uložena, ale také díky tomu, že je Streamem, i poslána např. pomocí HTTP protokolu na zcela jiný počítač. Serializovatelné typy, musí být i ty, které jsou používány při takzvaném remotingu, což je možnost používat objekty mezi různými aplikačními doménami. Opačnému procesu, tedy procesu pří kterém je z nějakého proudu vytvořena instance, se naopak říká Deserializace.

Jak učinit typy serializovatelnými?

K tomu, abychom naše typy učinili serializovatelnými (schopnými se serializovat) vedou dvě cesty. První cestou je použití atributu System.Serializable, což je cesta jednodušší a v obvyklých aplikacích častěji používaná. Druhým způsobem je nechat námi vytvářený typ implementovat rozhraní System.ISerializable. My se dnes budeme zabývat použitím atributu Serializable. V případě použití tohoto atributu na náš typ se o průběh serializace instance tohoto typu kompletně postará běhové prostředí .NET runtime. Takže pokud bychom chtěli mít třídu představující osobu a chtěli bychom, aby bylo možné instance této třídy serializovat, provedeme to jednoduše takto :

/// <summary>
/// Ukazkova trida predstavujici osobu, jejiz instance mohou byt serializovany
/// </summary>
[Serializable]
public class Osoba
{
 private DateTime datumNarozeni;
 private string jmeno;
 private string prijmeni;

 public Osoba(string Jmeno, string Prijmeni, DateTime DatumNarozeni)
 {
  this.jmeno = Jmeno;
  this.prijmeni = Prijmeni;
  this.datumNarozeni = DatumNarozeni;
 }

 //zbytek tridy
}

V případě této výchozí serializace ( = použití atributu Serializable) jsou serializovány všechny datové členy daného typu a to včetně těch soukromých. Je důležité vědět, že všechny typy, kterých jsou datové členy daného typu musí být taktéž serializovatelné. Pokud by tomu tak nebylo a pokusili bychom se o serializaci, došlo by k vyhození výjimky System.Runtime.Serialization.SerializationException.

/// <summary>
/// Tato trida by nemohla byt serialozovana protoze obahuje datovy clen
/// ktery nelze serializovat
/// </summary>
[Serializable]
public class NemoznaSerializace
{
 NeserializovatelnyTyp clen;
}

public struct NeserializovatelnyTyp
{
 //implementace typu
}

I když je třída označena atributem Serializable, její datový člen není a proto ji nelze serializovat. V případě naší ukázkové třídy Osoba, není se serializací problém, protože všechny typy datových členů (String a DateTime), jejichž definici obsahuje, jsou označeny jako serializovatelné.

Jak instanci serializovat?

Nyní když víme jakým způsobem učinit typ serializovatelným a také jaké je potřeba dodržet pravidla, potřebujeme ještě vědět jak vlastní serializaci provedeme. Ve jmenném prostoru System.Runtime.Serialization se nachází rozhraní IFormatter, které předepisuje funkcionalitu pro formátování serializovaných objektů. Přesněji, obsahuje předpis pro metody Serialize a Deserialize, které zařizují, jak název napovídá, vlastní serializaci respektive deserializaci. V základní knihovně tříd .NET frameworku jsou pro naše použití k dispozici dvě základní implementace tohoto rozhraní a to třídy BinaryFormatter a SoapFormatter.

 

 

BinaryFormatter je implementace, která serializuje a desearilizuje objekty v binárním formátu a nalezneme ji ve jmenném prostoru System.Runtime.Serialization.Formatters.Binary. SoapFormatter zase serializuje a deserializuje objekty do formátu SOAP, což je v podstatě implementace XML a nachází se ve jmenném prostoru System.Runtime.Serialization.Formatters.Soap. Následující příklad demostruje použití serializace instance třídy Osoba do binárního formátu, tedy pomocí třídy BinaryFormatter.

public static void Serializace()
{
 DateTime lDate = new DateTime(1984,2,9);
 Osoba lOsoba = new Osoba("Jan","Novak",lDate);
Stream lStream = new FileStream("C:/test.bin",FileMode.Create);
 IFormatter lFormatter = new BinaryFormatter();
 try
 {
  lFormatter.Serialize(lStream,lOsoba);
 }
 finally
 {
  lStream.Close();
 }

}

Metodě Serialize předáme ve formě parametrů referenci na Stream, který vede ke konkrétnímu úložišti a samotnou instanci, kterou chceme serializovat. V našem případě jsme nechali instanci serializovat do souboru. A jak instanci deseralizujeme? To už ukazuje tento příklad :

public static void Deserializace()
{
 IFormatter lFormatter = new BinaryFormatter();
 Stream lStream = new FileStream("C:/test.bin",FileMode.Open);
 Osoba lOsoba = null;
 try
 {
  lOsoba = (Osoba) lFormatter.Deserialize(lStream);
  Console.WriteLine("Deserializovana osoba je {0} {1}",lOsoba.Jmeno,lOsoba.Prijmeni);
 }
 finally
 {
  lStream.Close();
 }
}

Deserializace instance je také velmi jednoduchá záležitost. Jediné co metodě Deserialize musíme předat je odkaz na Stream vedoucí k úložišti instance.

Pokud bychom chtěli instanci serializovat do formátu SOAP, jediné co bude ve zdrojovém kódu jiné bude záměna použité instance třídy BinaryFormatter za instanci třídy SoapFormatter. Obecně platí, že pro serializaci do souboru je vhodnější použít binární formát, protože výsledný soubor je o dost menší a mimo to také výrazně rychlejší.

Příští díl bude opět pojednávat o serializaci. Dozvíme se jak mít serializaci více pod kontrolou a zjistíme, že není nutné serializovat všechny datové členy instance typu.

Zdrojové kódy k příkladům naleznete zde.

Diskuze (2) Další článek: Chystá se senzační akvizice: hodlá eBay spolknout Skype Technologies?

Témata článku: , , , , , , , , , , , , , , , ,