Andmete konverteerimine ja seriaaliseerimine .Net raamistiku vahenditega

From EIK wiki

Eesmärk

Õpiobjekti eesmärgiks on tutvustada õppijale lähemalt andmete konverteerimise võimalusi ning anda lühiülevaade andmete serialiseerimisvõimalustest .Net raamistiku vahendite abil.

  • Andmete konverteerimine Convert klassi abil
  • Andmete konverteerimine TryParse meetodi abil
  • Andmete serialiseerimine
  • Objektide serialiseerimine
  • XML serialiseerimine

Andmete konverteerimine

Andmete konverteerimine ühest andmetüübist teise on programmeerises äärmiselt vajalik ning reaalses töös läheb seda tihti vaja. See vajadus on üsna selge ja arusaadav kui meil on vaja esitada andmeid erineval kujul. Kuid inimesed ei adu tihti, et andmete konverteerimist teostatakse tihti ka siis, kui programmeerija seda otseselt ei taju: näiteks kui me võrdleme täisarvu ja reaalarvu (int ja double tüüpi muutujaid), siis nende andmete tegelikuks võrdlemiseks tuleb teisendada täisarv reaalarvuks ning alles seejärel toimub võrdlemine.


Näide:

// loon int tüüpi muutuja taisArv
int taisArv = 3;
// loon double tüüpi muutuja murdarv
double murdArv = 3.1;
// võrdlen taisArv ja murdArv väärtuseid
if (murdArv > taisArv)
    Console.WriteLine("murdArv on suurem");


Selleks, et näites toodud võrdlemine saaks toimuda teisendatakse taisArv tegelikkuses double tüüpi väärtuseks, kui programmeerijat sellest ei teavitata, sest int tüüpi väärtused on double tüüpi väärtustele lähedased ning toimub automaatne vormindamine teise tüüpi. Samas, kui andmetüübid ei ole lähedased ja konverteerimisel võib esineda erisusi, siis tuleb programeerijal andmete konverteerimisele pöörata tähelepanu, sest muidu ei ole näiteks võrdlemine võimalik.

Näide:

//int vs string näide
// loon int tüüpi muutuja taisArv
int taisArv2 = 3;
// loon string tüüpi objekti nrTekst
string nrTekst = "4";
// võrdlen taisArv ja murdArv väärtuseid
if (taisArv2 > nrTekst)
    Console.WriteLine("taisArv2 on suurem");
//kompileerimisel tekib viga


Selleks, et selline võrdlemine oleks võimalik, tuleb andmetüübid ühesuguseks konverteerida. Nüüd on kaks võimalust: konverteerida string tüüpi väärtus int tüüpi väärtuseks või konverteerida int tüüpi väärtus string tüüpi väärtuseks. Kuna arvulisi väärtuseid on parem võrrelda, siis kasutame hetkel esimest võimalust.


Näide:

// loon int tüüpi muutuja taisArv
int taisArv2 = 3;
// loon string tüüpi objekti nrTekst
string nrTekst = "4";
// võrdlen taisArv ja murdArv väärtuseid
if (taisArv2 > Convert.ToInt32(nrTekst)) 
    Console.WriteLine("taisArv2 on suurem");
//kompileerimisel ei teki viga

Convert klassi abil andmete konverteerimine

Konverteerimine on võimaluse korral ühes andmeformaadis oleva väärtuse teisendamine teise andmeformaati. Näiteks: kui meil on olemas string taht, milline hoiab väärtust „3“, siis me ei saa, seda väärtust omistada otse täisarvtüüpi muutujale. Eelnevalt tuleb teostada tüübiteisendus.


Näide:

string lause = "33";
int arv = lause; //tekib viga

Üks võimalus konverteerimiseks on kasutada System.Convert nimeruumi tööriistu:


Näide:

string lause = "33";
int arv = System.Convert.ToInt32(lause); // ei teki viga

System.Convert nimeruumis on olemas kõik vajalikud tööriistad kõigi enamlevinud andmetüüpide konverteerimiseks mõnda teise andmetüüpi objektiks.

GetTypeCode	Tagastab tüübikoodi
ToBoolean	Tagastab tõeväärtustüübi
ToByte	Tagastab bait-tüüpi väärtuse
ToChar	Tagastab tähemärgi
ToDateTime	Tagastab DateTime tüüpi väärtuse
ToDecimal	Tagastab decimal tüüpi väärtuse
ToDouble	Tagastab double tüüpi väärtuse
ToInt16	Tagastab short tüüpi väärtuse
ToInt32	Tagastab int tüüpi väärtuse
ToInt64	Tagastab long tüüpi väärtuse
ToSByte	Tagastab sbyte tüüpi väärtuse
ToSingle	Tagastab single tüüpi väärtuse
ToString	Tagastab string tüüpi väärtuse
ToUInt16	Tagastab ushort tüüpi väärtuse
ToUInt32	Tagastab int tüüpi väärtuse

ToUInt64 Tagastab ulong tüüpi väärtuse


Selleks, et võimaldada omaloodud andmetüüpide teisendamist Convert nimeruumi vahenditega, peab sellel klassil olema realiseeritud IConvertible liides. 

TryParse meetodi abil andemete konverteerimine

Convert nimeruumi abil andmete konverteerimine on küll mugav, kuid võib samas põhjustada ootamatuid probleeme. Näiteks kui kasutaja sisestab numbri asemel sõna või tähe, siis tekib numbriliseks väärtuseks teisendamisel probleem, sest Convert.ToInt32 meetod näiteks eeldab, et teisendatakse ainult neid tekstilisi väärtuseid, mis kosnevad ainult numbreid kujutatavatest sümbolitest (0123456789) muul juhul tekib viga.

Näide:

string mitteSobivLause = "123ABC"; 
int arv2 = Convert.ToInt32(mitteSobivLause);
// Konverteerimisel tekib viga


Kui see viga on nüüd haldamata, siis rakendus lõpetab töö, vea püüdmiseks ning sellega tegelemiseks tuleb kasutada try ... catch plokke.


Näide:

string mitteSobivLause = "123ABC";
int arv2 = 0;
try
{
    arv2 = Convert.ToInt32(mitteSobivLause);
    // Konverteerimisel tekib viga
}
catch (Exception viga)
{
    Console.WriteLine("Tekkis viga: " + viga.Message);
}


Sellisel, näites toodud, juhul rakendus ei hangu ning kasutajat teavitatakse veast, kuid teisendamine jääb siinkohal tegemata ning tekkida võiva veaga tuleb rakenduse ülesehituse juures juba algselt arvestada. Samas võib konverteerimist teostada ka andmetüübi staatilise meetodiga TryParse.


Näide

string mitteSobivLause2 = "123ABC";
int arv3;
if (int.TryParse(mitteSobivLause2, out arv3))
{
    // Kui siia jõuti, siis konverteerimine õnnestus ja saab
    // planeeritud tegevustega edasi minna
    Console.WriteLine("Koverteerimine õnnestus");
}
else
{
    // Kui siia jõuti, siis konverteerimine ei õnnestunud
    Console.WriteLine("Koverteerimine ei õnnestunud!");
}


TryParse meetodi kasutamine on veaohtlikes kohtades enamasti eelistatud ning võimaldab luua lihtsamaid programmistruktuure ning seeläbi hoida programmi ülesehitus lihtsana. Samas tarbitakse sellisel juhul ka vähem ressursse, sest vigade püüdmine ja haldamine on alati kulukas tegevus.

Andmete serialiseerimine

Andmete ja objektide salvestamiseks ja edastamiseks teistele rakendustele tuleb objektid ja andmed serialiseerida. Serialiseerimiseks on .Net raamistikus mitmeid erinevaid tehnoloogiaid: on võimalik kasutada näiteks binaarset serialiseerimist, SOAP või ka XML formaati konverteerimist.

Serialiseerimiseks mõeldud vahendid ja meetodid on koondatud System.Runtime.Serialization ja System.Xml.Serialization nimeruumidesse.

Serialiseerimise käigus konverteeritakse objektid ja andmed selliselt, et need oleks järjestikuliselt esitatavad ning seejärel on võimalik saadud tulem salvestada või edastada. Deserialiseerimise käigus taastatakse objektide ja andmete serialiseerimise eelne seisund.


Näiteks: kui rakenduses tekib vajadus mingisuguse objekti seis faili salvestada, siis on võimalik see objekt serialiseerida ning saadud tuleb näiteks faili salvestada. Hiljem on aga võimalik info failist lugeda ning deserialiseerida ning objekt taastada.


Objektide binaarne serialiseerimine

Kõige lihtsamal juhul tuleb objekti serialiseerimiseks teha järgmist:

  • Luua voo objekt (stream object), mis võimaldaks serialiseeritud info hoiustamist.
  • Luua BinaryFormatter tüüpi objekt, mis võimaldab binaarset serialiseerimist teostada (asub: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter)
  • Kutsuda välja BinaryFormatter objekti meetod Serialize


Näide:

// Loon paisktabeli aadressid
Hashtable aadressid = new Hashtable();
//Täidan loodud tabeli kolme kirjega
aadressid.Add("Jeff", "123 Main Street, Redmond, WA 98052");
aadressid.Add("Fred", "987 Pine Road, Phila., PA 19116");
aadressid.Add("Mary", "PO Box 112233, Palo Alto, CA 94301");

// Loon vooobjekti, kuhu on võimalik, serialiseerimise tulemus salvestada
// Antud näites on selleks FileStream objekt, mis võimaldab
// Andmed kettale salvestada
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);

// Loon BinaryFormatter tüüpi objekti,
// mida kasutan paisktabeli serialiseerimiseks
BinaryFormatter formatter = new BinaryFormatter();
try
{
    formatter.Serialize(fs, aadressid);
}
catch (SerializationException e)
{
    Console.WriteLine("Tekkis viga: " + e.Message);
    throw;
}
finally
{
    fs.Close();
}


Objektide deserialiseerimiseks (ehk taastamiseks) on vaja

  • Luua voo objekt andmete lugemiseks
  • Luua BinaryFormatter tüüpi objekt, mis võimaldab binaarset serialiseerimist teostada
  • Luua uus objekt, kuhu deserialiseeritav objekt (või objektid hoiustada)
  • Kutsuda välja BinaryFormatter objekti meetod Deserialize

Näide:

// objektid hoiustada
Hashtable addresses = null;

// Avan faili, kuhu andmed on salvestatud.
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
    BinaryFormatter formatter = new BinaryFormatter();

    // Taasstan serialiseeritud paisktabeli
    addresses = (Hashtable)formatter.Deserialize(fs);
}
catch (SerializationException e)
{
    Console.WriteLine("Tekkis viga: " + e.Message);
    throw;
}
finally
{
    fs.Close();
}

// Väljastan taastatud paistabeli kirjed.
foreach (DictionaryEntry de in addresses)
{
    Console.WriteLine("{0} elab aadressil: {1}.", de.Key, de.Value);
}

XML serialiseerimine

XML formaadis serialiseerimise protsess sarnaneb paljuski binaarsele serialiseerimisele, kui d oluline erinevus seisneb selles, et XML kujul andmeid on erinevate rakenduste vahel oluliselt lihtsam vahetada ning tulem on inimesele arusaadav (ehk serialiseeritud kujul andmed on inimesele loetavad.)


Kõige lihtsamal juhul tuleb objekti XML formaadis serialiseerimiseks teha järgmist:

  • Luua voo objekt (stream object), mis võimaldaks serialiseeritud info hoiustamist.
  • Luua XmlSerializer tüüpi objekt, mis võimaldab XML serialiseerimist teostada (asub: System.Xml.Serialization.XmlSerializer)
  • Kutsuda välja XmlSerializer objekti meetod Serialize


Näide

// Loon DateTime objekti aeg ning kirjutan sinna hetkeaja
DateTime aeg = DateTime.Now;

// Loon vooobjekti, kuhu on võimalik, serialiseerimise tulemus salvestada
// Antud näites on selleks FileStream objekt, mis võimaldab
// Andmed kettale salvestada
FileStream fs = new FileStream("DataFile.xml", FileMode.Create);

// Loon XmlSerializer tüüpi objekti,
        
// mida kasutan DateTime objekti XML formaadis serialiseerimiseks
XmlSerializer xmlSerialiseerija = new XmlSerializer(typeof(DateTime));
try
{
    xmlSerialiseerija.Serialize(fs, aeg);
            
}
catch (SerializationException e)
{
    Console.WriteLine("Tekkis viga: " + e.Message);
    throw;
}
finally
{
    fs.Close();
}


Obejktide deserialiseerimiseks (ehk taastamiseks) on vaja

  • Luua voo objekt andmete lugemiseks
  • Luua XmlSerializer tüüpi objekt, mis võimaldab binaarset serialiseerimist teostada
  • Luua uus objekt, kuhu deserialiseeritav objekt (või objektid hoiustada)
  • Kutsuda välja XmlSerializer objekti meetod Deserialize


Näide:

//Loon XDocument tüüpi objekti, ning loen DateFile.xml faili mällu
// Kirjutan saadud andmed konsooli
XDocument xDoc = XDocument.Load("DataFile.xml");
Console.WriteLine(xDoc);
        
// Loon uue  DateTime tüüpi objekti kuhu saab hiljem deserialiseeritud
// objekti hoiustada
DateTime aeg;

// Avan faili, kuhu andmed on salvestatud.
FileStream fs = new FileStream("DataFile.xml", FileMode.Open);
try
{
    XmlSerializer xmlSerialiseerija = new XmlSerializer(typeof(DateTime));

    // Taasstan serialiseeritud DateTime
    aeg = (DateTime)xmlSerialiseerija.Deserialize(fs);
    Console.WriteLine("Aeg oli: " + aeg.ToLongTimeString());
}
catch (SerializationException e)
{
    Console.WriteLine("Tekkis viga: " + e.Message);
    throw;
}
finally
{
    fs.Close();
}