IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 10 - Serializace a deserializace v C# .NET

V minulé lekci, LINQ to XML v C# .NET, jsme si představili technologii LINQ to XML.

V dnešním C# .NET tutoriálu si řekneme něco o serializaci a deserializaci.

Serializace je uchování stavu objektu. Trochu odborněji by se to dalo popsat jako konvertování objektu na proud bytů a poté uložení někde do paměti, databáze nebo souboru. Deserializace je opak serializace. Dalo by se říci, že tedy převedete zpátky proud bytů na kopii objektu.

K čemu je to dobré?

Serializace vám umožní uložit stav objektu a potom pomocí deserializace si ho kdykoliv znovu vytvořit. Pomocí serializace se třeba posílají data skrz síť nebo se ukládá nastavení aplikace.

Ukázková aplikace

Založíme si nový projekt typu Windows Forms Application. Poté si vytvoříme nějakou třídu, její instanci bychom chtěli zachovat a při opětovném spuštění aplikace ji mít ve stavu, v jakém jsme ji při zavření aplikace zanechali. Třídu nazveme Uzivatel a dáme jí vlastnosti Jmeno, Prijmeni a DatumNarozeni. Třída by teda mohla vypadat nějak takto (všimněte si, že je veřejná):

public class Uzivatel
{
    public string Jmeno { get; set; }
    public string Prijmeni { get; set; }
    public DateTime DatumNarozeni { get; set; }
}

Na hlavní formulář si přidáme tedy dva TextBoxy na jméno a příjmení. Ještě si přidáme ovládací prvek DateTimePicker, abychom mohli určit datum uživatele. Dále si někde umístíme tlačítko, kterým budeme přidávat uživatele do naší aplikace. Přidáme prvek ListBox pro zobrazení uživatelů. Nakonec si přejmenujeme naše ovládací prvky ze základního jména na nějaké, abychom se v nich vyznali. Viz. obrázek.

Pojmenování komponent ukázkové aplikace na serializaci ve Visual Studio - Soubory v C# .NET

Dále si vytvoříme kolekci typu List<Uzivatel>, abychom měli uživatele kde v aplikaci uchovávat. Přesuneme se tedy do kódu hlavního formuláře (Form1 nebo u mě FormMain) a dopíšeme si do třídy tuto privátní kolekci.

private List<Uzivatel> uzivatele = new List<Uzivatel>();

Přesuneme se zpátky do designeru formuláře a přidáme si metodu k události Click u ovládacího prvku btnPridej. Dopíšeme zde kód, který přidá uživatele do naší kolekce. Dále ještě musíme ukázat uživatele v listBoxUzivatele. K tomu nám poslouží vlastnost DataSource.

private void btnPridej_Click(object sender, EventArgs e)
{
    // Vytvoříme nového uživatele s daty z našich kontrolek
    Uzivatel uzivatel = new Uzivatel
    {
        Jmeno = tbJmeno.Text,
        Prijmeni = tbPrijmeni.Text,
        DatumNarozeni = dateTimePicker.Value
    };
    // Přidáme ho do naší kolekce
    uzivatele.Add(uzivatel);
    // Obnovíme zdroj dat našeho listBoxUzivatele
    listBoxUzivatele.DataSource = null;
    listBoxUzivatele.DataSource = uzivatele;
}

Teď již máme vcelku funkční aplikaci. Když aplikaci spustíte a zkusíte uživatele přidat, uvidíte, že se přidala vlastně jen položka "NazevProjektu.Uzivatel". Přesuneme se tedy do souboru Uzivatel a přepíšeme metodu ToString(). Třeba nějak takto:

public override string ToString()
{
    return "Jméno: " + Jmeno +
        " Přijmení: " + Prijmeni +
        " Datum Narození: " + DatumNarozeni.ToShortDateString();
}

Zkuste si přidat uživatele teď a vidíme, že se uživatel zobrazuje lidštěji.

Serializace

Nyní konečně můžeme přejít k serializaci dat. Vytvoříme si tedy metodu Serializuj() v kódu formuláře.

private void Serializuj()
{
    try
    {
        // Vytvoříme si XmlSerializer na typ List<Uzivatel>
        XmlSerializer serializer = new XmlSerializer(uzivatele.GetType());

        // Alternativní forma, jak by to šlo také zapsat
        //XmlSerializer serializer = new XmlSerializer(typeof(List<Uzivatel>));

        // Vytvoříme Stream pomocí kterého budeme serializovat
        using (StreamWriter sw = new StreamWriter("uzivatele.xml"))
        {
            // Zavoláme metodu Serialize(), kde první parametr je Stream
            // Ten jsme vytvořili o řádek výše
            // Druhý parametr je objekt, který serializujeme
            serializer.Serialize(sw, uzivatele);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Využili jsme serializer do formátu XML. Serializerů je několik typů včetně binárního, poskytuje nám je již připravené .NET framework. Nemusíme se tedy starat o nic, instance se serializují automaticky. Nyní se vrátíme zpátky do designeru a u formuláře najdeme Event (událost) OnClosing, 2x klikneme a v obslužném kódu zavoláme naší metodu Serializuj().

private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
    Serializuj();
}

Pozn. Název metody se může lišit podle názvu hlavního formuláře. Jestli jste jeho jméno neupravovali, budete mít na začátku nejspíš prefix Form1.

Když nyní spustíme program, přidáme nějaké uživatele a program zavřeme, kolekce uživatelů se serializuje a uloží do NazevProjektu/Bin/Debug/uzivatele.xml. Když soubor otevřeme, měl by být čitelný. U mě soubor vypadá nějak takto:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfUzivatel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Uzivatel>
    <Jmeno>Jan</Jmeno>
    <Prijmeni>Novák</Prijmeni>
    <DatumNarozeni>2013-07-11T17:27:19</DatumNarozeni>
  </Uzivatel>
  <Uzivatel>
    <Jmeno>Jakub</Jmeno>
    <Prijmeni>Špatný</Prijmeni>
    <DatumNarozeni>2013-07-11T17:27:19</DatumNarozeni>
  </Uzivatel>
</ArrayOfUzivatel>

Deserializace

Serializaci máme, tak teď ještě deserializaci. Z pohledu na kód je to trošku těžší, proto raději všechno vysvětlím ještě jednou. Vytvoříme metodu Deserializuj() v kódu hlavního formuláře. Nejprve musíme zjistit, jestli vůbec daný XML soubor s daty existuje. K tomu nám poslouží třída File a metoda Exists(string path), která vrací bool. Do těla podmínky už vytvoříme XmlSerializer na typ našeho Listu uživatelů. Dále vytvoříme StreamReader s cestou k našemu souboru a pak jen zavoláme metodu Deserialize() z třídy XmlSerializer. Je tu ale drobný detail, a to že metoda Deserialize() vrací object. Musíme zde tedy přetypovat, než přiřadíme uložené uživatele k našim stávajícím. Celá metoda tedy vypadá ve finále takto:

private void Deserializuj()
{
    try
    {
        if (File.Exists("uzivatele.xml"))
        {
            XmlSerializer serializer = new XmlSerializer(uzivatele.GetType());
            using (StreamReader sr = new StreamReader("uzivatele.xml"))
            {
                uzivatele = (List<Uzivatel>)serializer.Deserialize(sr);
            }
        }
        else throw new FileNotFoundException("Soubor nebyl nalezen");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Tuto metodu zavoláme v události formuláře Load. Přejdeme tedy do designeru a ve vlastnostech (properties) formuláře najdeme událost Load a vytvoříme její obslužnou metodu. V ní zavoláme naší metodu Deserializuj() a k tomu ještě potřebujeme načíst naše uživatele do našeho ListBoxu. Celá metoda vypadá tedy takto:

private void FormMain_Load(object sender, EventArgs e)
{
    Deserializuj();
    listBoxUzivatele.DataSource = uzivatele;
}

Pozn. Název metody se může lišit podle názvu hlavního formuláře. Jestli jste jeho jméno neupravovali, budete mít na začátku nejspíše prefix Form1.

Když aplikaci spustíte a naplníte daty, zavřete a znovu otevřete, měla by obsahovat všechny uživatele, které jste tam přidali.

Závěr

Na závěr bych chtěl říct pár věcí, na které nejspíš přijdete i sami, když budete serializovat objekty vaší aplikace.

  • Třída, kterou serializujete, musí obsahovat bezparametrický konstruktor (nebo žádný parametrický). Je to z toho důvodu, že deserializer si nejdříve vytvoří prázdnou instanci a potom postupně zadává vlastnosti jak je čte ze souboru (nebo jiného streamu).
  • Nemůžete serializovat ovládací prvky, ať již defaultní a nebo vámi vytvořenou (User Control). Kdybyste ale chtěli, určitě nepotřebujete serializovat úplně všechno, takže si můžete uložit jen ty věci, které opravdu potřebujete.
  • K serializaci patří několik atributů, jako:
    • [XmlIgnore] - Nebude vám danou propertu serializovat.
    • [Serializable()] - Dává se nad deklaraci třídy, dáváte tomu jasně najevo, že se bude objekt serializovat.(Im­plementuje interface ISerializable)
    • [XmlAttribute("Name")] změní XML element z párového na nepárový a hodnota dané property bude v atributu Name. Například <Uzivatel Name="Jan"> místo <Jmeno>Jan</Jmeno>.
  • Kdyby jste někdy chtěli serializovat třídu Color, tak ona se sice serializuje, ale v souboru nemá žádnou hodnotu, proto můžete např. serializovat Color jako hexadecimální číslo a při deserializaci si ho jednoduše překonvertujete na barvu.

V následujícím cvičení, Řešené úlohy k 6.-10. lekci práce se soubory v C# .NET, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 577x (58.1 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

Předchozí článek
LINQ to XML v C# .NET
Všechny články v sekci
Soubory v C# .NET
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 6.-10. lekci práce se soubory v C# .NET
Článek pro vás napsal Jan Vargovský
Avatar
Uživatelské hodnocení:
65 hlasů
H̴̢̡̛̫̙̖̦͍̥̺̳̪͖̺̫̲͇̗̹̠̥͈̭͔̻̗͚̭̥̝͐̋͒̆̾̅͒̈̐̀̒̔̇̈̔̆̎̔͐̊͆̆̐̊̈͆̂̐̓̓͛̌̈́̈́̅̅̔̚̕̚͠͝͝͝͝ì̸͇͖̹̯̤͇͍̹̥̅͗͆̄̌͆͑̓̈́̓̊̈́͋̈́͛͊͛͂̇͋͒̿̃͐͌̐̚͝͝͝͝͝͝.̶̧̡̧̧̖̫̯̞͖̯̩̠̭̩͇͔̤̱̜̠̠̙͉͉̼̱͓̣͍̱͎͕̦͓̫̗̮̦͍͚̗͕̥̳͚̬̯̞̟͇̻̺̙͙̜͖̰̊͒̌̌̚͜͜͝
Aktivity