Andmebaasipõhiste
veebirakenduste arendamine Microsoft Visual Studio
ja SQL Server ’i
baasil
C#Tallinn
2011
Sisukord
C# 4Põhivõimalused 5Käivitamine 8
Suhtlus arvutiga 9
Arvutamine 10
Valikud 11
Kordused 13
Korrutustabel 15
Alamprogramm 17
Massiivid 18
Käsud mitmes
failis 23
Tekst 24
Tekstifailid 27
Juhuarv 30
Omaloodud andmestruktuur 31
Edasijõudnute osa: Objektorienteeritud programmeerimine 35Tutvustus 35
Dokumenteerivad kommentaarid 41
Pärilus 44
Ülekate 47
Liidesed 48
Abstraktne klass 50
Meetodite asendus 52
Omadused 54
Indekseering 57
Struktuurne andmestik 59
Operaatorite üledefineerimine 67
Abivahendid 76Erindid 76
Enum 81
Andmekollektsioonid 82
Mallid 87
Atribuudid 90
Andmebaasiliides 95Ühenduse loomine, päring 95
Andmete lisamine 99
SQL-
parameeter 99
Salvestatud
protseduur 101
Funktsiooni delegaadid 103Funktsioonide komplekt 104
Sündmused 105
Ilmajaamad 105
Graafiline liides 108
Visual Studio C# Expressi install 110LINQ - .NET Language -Integrated Query 114Põhikonstruktsioonide näited 116Kokkuvõte 117
C#
Mõnigi võib
ohata, et jälle üks uus programmeerimiskeel siia ilma välja
mõeldud. Teine jälle rõõmustab, et midagi uut ja huvitavat
sünnib. Kolmas aga hakkas äsja veebilahendusi kirjutama ja sai
mõnegi ilusa näite
lihtsasti kokku. Oma soovide
arvutile selgemaks
tegemise juures läheb varsti vaja teada, "mis
karul kõhus on",
et oleks võimalik täpsemalt öelda, mida ja kuidas masin tegema
peaks. Loodetavasti on järgnevatel lehekülgedel kõigile siia
sattunute jaoks midagi
sobivat . Mis liialt lihtne ja igav tundub,
sellest saab kiiresti üle lapata. Mis esimesel pilgul paistab
arusaamatu, kuid siiski vajalik, seda tasub teist korda lugeda. Ning
polegi
loota , et kõik kohe lennult külge jääks!?
Selle jaoks on
teksti sees koodinäited, mida saab kopeerida ja arvutis tööle
panna. Ning mõningase muutmise ja katsetamise peale
avastada , mis
mille jaoks on ning kuidas seda oma kasuks rakendada saab. Töötav
näide on üks hea kindel tugipunkt nagu üks suur puu lagendikul,
kuhu oskab alati tagasi minna. Juhul, kui muutmistega on õnnestunud
oma koodilõik nii sõlme keerata, et see
sugugi enam töötada ei
taha, saab alati võtta materjalist taas algse töötava näite ning
sealt juurest katsetama hakata.
Kes
pikemalt mitmesuguseid rakendusi kirjutab, avastab mõne aja pärast, et samas
keeles kirjutatud programm võib vähemalt esmapilgul mõnevõrra
erinev välja näha sõltuvalt sellest, kas programm käivitatakse
veebist, tegutsetakse nuppudega ja tekstiväljadega aknas, väljundiks
on mobiiltelefon või
piirdub kogu tegevus tekstiaknaga. Esimesel
korral võib tunduda, et oleks nagu täiesti eri keeltes ja eri moodi
kirjutamine. Ühes kohas on alati koodi juures salapärane
button1_click,
teises public
static void Main ning kolmandas veel midagi muud. Aga
sellest ei tasu ennast väga häirida lasta.
Ehkki .
NETi ja C# juures
on püütud eri kohtades käivituvate rakenduste loomist sarnasemaks
muuta, tuleb siiski
kirjutamisel arvestada käivitumiskoha
võimalustega. Siin materjalis keskendume C# keele ülesehitusega
seotud teemadele, mis on ühised kõigi käivitumiskohtade puhul.
Ning kasutajaliidesena pruugime programmeerimisõpikute
traditsioonilist lihtsat ning väheste (eksimis)võimalustega
tekstiakent - nii jääb rohkem aega tähelepanu pühendada keele
enese konstruktsioonidele, mida siis edaspidi julgesti
veebirakenduste juures ja soovi korral mujalgi pruukida. Kes aga
tahab omale koodi kirjutamiseks rohkem abivalmis ning
lisavõimalustega keskkonda, sellele soovitame lugeda peatükki
nimega Visual Studio C# Expressi install – samm
sammult juhis
vastava keskkonna paigaldamiseks ning esimese
rakenduse käivitamiseks. Edasine kirjutamine sarnaselt konspektis olevale.
Põhivõimalused
Kui
rakendus juba
mingitki elumärki annab, on see tunduvalt rohkem, kui lihtsalt hulk
koodi, mis peaks "midagi arukat" tegema. Tunne, et suutsin
programmi ise, omade roosade kätega käima panna, on hea. Ja annab
kindlustunde, et järgmisel korral saab asi ainult paremaks minna.
Kui käima on lükatud, siis edasi võib mõtelda juba juurde
panemise peale. Nii nagu talumees, kes omale krati oli ehitanud, sai
hakata talle ülesandeid andma alles siis, kui
kratt hinge sisse
võttis. Muul juhul on tegemist palja põhuhunnikuga, millele
teivas sisse löödud ja vanad kartulikorvid külge riputatud - olgu need
nii suured ja vägevad tahes. Tööle hakkamiseks on hinge vaja. Aga
hinge ei saa enne sisse puhuda, kui väikegi tervik olemas. Ning C#
puhul näeb lühim tervikprogramm välja ligikaudu järgmine:
using System;
class Tervitus",
arv1,
arv2, arv1*arv2);
C:\Projects\oma\naited>Arvutus
Esimene
arv:
3
Teine
arv:
5
Arvude
3 ja 5 korrutis on 15
Ülesandeid
- Küsi kahe inimese nimed ning teata, et täna on nad pinginaabrid
- Küsi ristkülikukujulise toa seinte pikkused ning arvuta põranda pindala
- Leia 30% hinnasoodustusega hinna põhjal alghind
Valikud
Ehk võimalus
otsustamiseks, kui on vaja, et programm käituks kord üht-, kord
teistmoodi. Allpoololev näide koos väljundiga võiks näidata,
kuidas tingimuslause abil tehtud valik toimib.
using
System;<
else
while(tund23);
Console.WriteLine(" TubliD:\kodu\0606\opikc#>Kordus3
Sisesta
tund vahemikus 0-23
32
Sisesta
tund vahemikus 0-23
11
Tubli,
sisestasid 11.
Ülesandeid
* Trüki arvude ruudud ühest kahekümneni
* Küsi
kasutajalt viis arvu ning väljasta nende summa
* Ütle
kasutajale "Osta
elevant ära!". Senikaua korda küsimust,
kuni kasutaja lõpuks ise kirjutab "elevant".
Korrutustabel
... ehk näide,
kuidas eelnevalt vaadatud tarkused ühe programmi sisse kokku panna
ning mis selle peale ka midagi tarvilikku teeb.
Algul on näha,
kuidas otse programmi käivitamise juures ka mõned andmed sinna
kätte anda. Et kui
kirjutan Korrutustabel
4 5
siis saadakse
sellest aru, et soovin korrutustabelit nelja rea ja viie veeruga.
Nende käsurea parameetrite püüdmiseks on alamprogramm Main-i
ümarsulgudes koht string[]
argumendid. Kõik käsureale kirjutatud sõnad (ka
üksik number on arvuti jaoks sõna) pannakse sinna argumentide
massiivi ehk jadasse, kust neid järjekorranumbri järgi kätte saab.
Andmetüüp string[]
tähendabki, et tegemist on stringide ehk sõnede ehk tekstide
massiiviga. Kirjutades massiivi järgi .
Length ,
saab teada, mitu elementi selles massiivis on - mis praegusel juhul
on võrdne lisatud sõnade arvuga käsureal. Kõik sõnad saab ka
ükshaaval järjekorranumbri järgi kätte. Arvestama peab ainult, et
sõnu hakatakse lugema numbrist 0. Nii et kui eeldatakse, et tegemist
on kahe parameetriga, siis nende kättesaamiseks peame ette andma
numbrid null ja üks.
Nagu tingimusest
on näha: juhul kui argumente pole täpselt kaks, siis kasutatakse
vaikimisi ridade ja veergude arvu ning joonistatakse korrutustabel
suurusega 10 korda 10.
Tabeli
trükkimiseks on kaks for-tsüklit
paigutatud üksteise sisse. Selles pole midagi imelikku - iga rea
juures trükitakse kõik
veerud esimesest kuni viimaseni. Ning
selleks, et erinevate numbrite arvuga arvud meie tabelit sassi ei
lööks, on väljatrü. Ainsat Console.Write
argumenti (järjekorranumbriga 0) trükitakse nõnda, et ta võtaks
alati viis kohta.
using
System;<", a, b, Korruta(a, b));
Console.WriteLine(Korruta(3,
5));
C:\Projects\oma\naited>Alamprogramm
4
korda 6 on 24
15
Ülesandeid*
Koosta alamprogramm kahe arvu keskmise leidmiseks
* Koosta
alamprogramm etteantud arvu tärnide väljatrükiks.
Katseta .
* Küsi inimeselt
kolm arvu. Iga arvu puhul joonista vastav kogus tärne ekraanile
Massiivid
Kuna arvuti on
mõeldud suure hulga andmetega ümber käimiseks, siis on
programmeerimiskeelte juurde mõeldud ka vahendid nende
andmehulkadega toimetamiseks. Kõige lihtsam ja levinum neist on
massiiv . Iga elemendi poole saab tema järjekorranumbri abil
pöörduda. Algul tuleb määrata,
millisest tüübist andmeid
massiivi pannakse ning mitu kohta elementide jaoks massiivis on.
Järgnevas näites tehakse massiiv kolme täisarvu hoidmiseks.
Kusjuures nagu C-programmeerimiskeele sugulastele kombeks on,
hakatakse elemente lugema nullist. Nii et kolme massiivielemendi
puhul on nende järjekorranumbrid 0, 1 ja 2. Tahtes väärtusi sisse
kirjutada või massiivist lugeda, tuleb selleks kirja panna massiivi
nimi (praeguse juhul m) ning selle taha kandiliste sulgude sisse
järjekorranumber, millise elemendiga suhelda tahetakse.
using
System;<;
Array.Sort(m);
for(int
i=0; iMassiiv4
33
40
48
Osutid ja koopiad
Kui
ühe
hariliku täisarvulise muutuja väärtus omistada teisele, siis
mõlemas muutujas on koopia
samast väärtusest ning toimingud ühe
muutujaga teise väärtust ei mõjuta. Massiividega ning tulevikus ka
muude objektidega tuleb tähelepanelikum olla. Kui üks massiiv
omistada teisele, siis tegelikult kopeeritakse vaid massiivi osuti,
mõlema muutuja kaudu pääsetakse ligi tegelikult samadele
andmetele. Nagu järgnevas näites: massiivid m2
ja m
näitavad samadele andmetele. Kui ühe muutuja kaudu andmeid muuta,
siis muutuvad ka teise muutuja kaudu nähtavad andmed nagu väljatrüki
juures paistab. Algselt on massiivi m
ja m2
elemendid 40, 48, 33. Pärast massiivi m elemendi number 1
muutmist 32ks, on ka massiivi m2
elemendid muutunud - väärtusteks 40, 32, 33. Nõnda on suurte
andmemassiivide juures teise muutuja tegemine andmete juurde
pääsemiseks arvuti jaoks kerge ülesanne. Samas aga peab vaatama,
et vajalikke andmeid kogemata ettevaatamatult ei muudaks. <;
int[]
m2=m; //
Viide samale massiivile
Tryki(m2);
m[1]=32;
Tryki(m2);
Kui soovida, et
kaks algsetest andmetest pärit massiivi on üksteisest sõltumatud,
siis tuleb teha algsest massiivist koopia (kloon).
int[]
m3=(int[])m.Clone(); //Andmete koopia
m[1]=20;
Tryki(m3);
Pärast
kloonimist muutused massiiviga m enam massiivi m3 väärtusi ei
mõjuta.
Soovides massiivi
tühjendada, aitab klassi Array käsklus
Clear , mis täisarvude puhul
kirjutab etteantud vahemikus (ehk praegusel juhul kogupikkuses, 0 ja
Length-i vahel) täisarvude puhul väärtusteks
nullid .
Array.Clear(m3,
0, m3.Length); //Tühjendus
Massiivist
andmete otsimiseks sobib käsklus IndexOf.
Soovitud elemendi leidumise korral väljastatakse selle elemendi
järjekorranumber. Otsitava puudumisel aga -1.
Console.WriteLine(Array.IndexOf(m,33));
Console.WriteLine(Array.IndexOf(m,17));
//
puuduv element
using
System;<,<
Console.WriteLine(m[0,
1]); //48
Console.WriteLine("M66dete
arv: "+m.
Rank );
Console.WriteLine("Ridade
arv: "+m.GetLength(0));
Console.WriteLine("Veergude
arv: "+m.GetLength(1));
//elemente
mõõtmes nr. 1
int
summa=0;
foreach(int
arv in m){
summa+=arv;
Console.WriteLine("Summa:
"+summa);
C:\Projects\oma\naited>Massiiv8
48
M66dete
arv: 2
Ridade
arv: 2
Veergude
arv: 3
Summa:
197
Ülesandeid* Küsi kasutaja
käest viis arvu ning väljasta need tagurpidises järjekorras.
* Loo
alamprogramm massiivi väärtuste aritmeetilise keskmise leidmiseks.
Katseta.
* Loo
alamprogramm, mis suurendab kõiki massiivi elemente ühe võrra.
Katseta.
* Sorteeri
massiiv ning väljasta selle keskmine element.
* Koosta
kahemõõtmeline massiiv ning täida korrutustabeli väärtustega.
Küsi massiivist kontrollimiseks väärtusi.
Käsud mitmes failis
Suuremate
programmide puhul on täiesti loomulik, et kood jagatakse mitme faili
vahel. Nii on hea jaotuse puhul kergem orienteeruda. Samuti on mugav
terviklike tegevuste plokke muudesse programmidesse ümber tõsta,
kui see peaks vajalikuks osutuma. Siin näites on kaks lihtsat
arvutustehet omaette abivahendite klassis välja toodud.<);
foreach(string
linn in linnad){
Console.WriteLine(linn);
Console.WriteLine(String.Join(";
", linnad));
D:\kodu\0606\opikc#>Tekst3
Tallinn
Tartu
Narva
Tallinn;
Tartu; Narva
Ülesandeid
* Trüki inimese
nime eelviimane täht
* Teata, kas
sisestatud nimi algab A-ga
* Trüki
sisestatud nimi välja suurtähtedega
* Teata, kas
lauses leidub sõna "ja"
* Asenda
olemasolu korral "ja" sõnaga "ning" ja teata
asendusest
* Trüki välja
lause kõige pikem sõna
Tekstifailid
Kui samu
lähteandmeid on vaja korduvalt kasutada, siis on neid igakordse
sissetoksimise asemel mugavam sisse lugeda
failist . Samuti on
suuremate andmemahtude korral hea, kui sisendi ja väljundi andmed
jäävad alles ka masina väljalülitamise järel. Keerukama
struktuuriga andmete ning mitme üheaegse kasutaja korral (näiteks
veebirakendustes) kasutatakse enamasti andmebaasi. Käsurea- või
iseseisva graafilise rakenduse puhul on
tekstifail aga lihtne ja
mugav
moodus andmete hoidmiseks. Samuti on ta tarvilik juhul, kui
juba pruugitakse eelnevalt
tekstifaili kujul olevaid andmeid.
Kirjutamine
Andmete faili
saatmiseks tuleb kõigepealt moodustada
voog etteantud nimega faili
kirjutamiseks. Edasine trükk toimub juba sarnaselt ekraaniväljundiga
Write
ning WriteLine
käskude abil. Lõppu tuleb kindlasti lisada käsklus
Close ,
et teataks hoolitseda andmete füüsilise kettale jõudmise eest ning
antakse fail vabalt kasutatavaks ka ülejäänud programmide jaoks.
Siinse näite tulemusena tekib käivituskataloogi lihtne fail nimega
"inimesed.txt", kuhu
kirjutatakse kaks nime. Tekstiekraanil
enesel pole käivitamise järel midagi näha - aga see veel ei
tähenda, nagu programm midagi ei teeks. Lihtsalt tema töö tulemus
jõuab loodavasse faili.
using
System;
using
System.IO;<
Kui tegemist
pikemate andmetega, siis ei tasu end sellest näilisest lihtsusest
eksitada lasta. Siis on jupikaupa andmete lugemine, töötlemine ja
kirjutamine ikka omal kohal. Kui aga on vaja mõni ettejäänud tekst
lihtsalt kettale
salvestada , siis piisab siinsest lihtsast käsust
täiesti.
Lisamine
Kui
FileMode.Create
asendada seadega FileMode.Append, siis jäävad
kirjutades vanad andmed alles. Uued read lihtsalt lisatakse
olemasoleva teksti lõppu. Sellist lisamist läheb tarvis näiteks
sündmuste logi kirjutamise juures.
using
System;
using
System.IO;<
Lugemine
Faili lugemisel
on
vood teistpidi. Create
ja Write
asemel on
Open ja Read.
Ning StreamWriteri
asemel StreamReader.
Voost tuleva iga ReadLine
tulemusena antakse üks tekstirida failist. Kui faili andmed
lõppesid, saabub ReadLine
käsu tulemusena tühiväärtus null. Selle järgi saab
programmeerija otsustada, et fail sai läbi.
using
System;
using
System.IO;<
Kui vaja faili
ridadega ükshaaval midagi ette võtta, siis kannatab nad käsuga
ReadAllLines lugeda ühte massiivi. Edasi on juba vabad käed edasi
toimetamiseks.
using System;
using
System.IO;<;
Console.WriteLine(nimed[r.Next(nimed.Length)]);
//Juhuslik nimi
D:\kodu\0606\opikc#>Juhuarv1
0,74339002358885
11
95
Kati
Ülesandeid*
Trüki juhuslike teguritega korrutamisülesanne
*
Kontrolli, kas kasutaja pakutud vastus oli õige
* Sõltuvalt
vastuse õigsusest lase
arvutil pakkuda olemasolevate hulgast valitud
kiitev või julgustav kommentaar.
Omaloodud andmestruktuur
Standardandmetüüpe
on .NET raamistikus kätte saada palju. Klasside arvu loetakse
tuhandetes. Sellegipoolest juhtub oma rakenduste puhul
olukordi , kus
tuleb toimetada andmetega, mille hoidmiseks mugavat moodust pole
olemas. Või siis on keegi kusagil selle küll loonud, aga lihtsalt
ei leia üles.
Harilike muutujate ja massiivide abil saab küll kõike
arvutis ettekujutatavat hoida. Vahel aga on mugavam, kui pidevalt
korduvate sarnaste andmete hoidmiseks luuakse eraldi andmetüüp.
Siis on teada, et kokku kuuluvad andmed püsivad kindlalt ühes kohas
koos ning pole nii suurt muret, et näiteks kahe firma andmed
omavahel segamini võiksid minna.
Järgnevas näites
kirjeldatakse selliseks omaette andmestruktuuriks punkt tasandil,
kaks täisarvulist muutujat asukohti määramas.
struct
Kui aga vähemalt
üks programmeerija loodud konstruktor on olemas, siis seda
nähtamatut konstruktorit ei tehta. Päriluse puhul kutsutakse
alamklassi eksemplari loomisel alati välja ülemklassi konstruktor.
Vaikimisi võtab kompilaator selleks ülemklassi parameetritega
konstruktori. Kui see aga puudub või soovitakse käivitada mõnda
muud, siis tuleb sobiva konstruktori väljakutse alamklassi juures
ära märkida. Siin märgitakse näiteks Modelli
loomise juures, et Modelli
isendi loomise juures tehakse kõigepealt valmis baasklassi (inimese) isend , kellele siis Modelli
enese konstruktoris vajalikud lisandused juurde pannakse. Ülemklassi
konstruktori määramine on kohe Modelli
konstruktori juures. Pärast koolonit olev base(vanus)
ütleb, et kasutatagu inimese puhul seda konstruktorit, kus tuleb
täisarvuline vanus kohe ette öelda.
public
Modell(int vanus, int uymberm66t):base(vanus){
ymberm66t=uymberm66t;
Ehkki
praegu tegelikult muud võimalust
polnudki , tuleb see ikkagi arvutile
ette öelda.
using
System;<
public
override void YtleVanus(){
Console.WriteLine("Minu
vanus on "+(vanus-5)+" aastat"); <
public
void Tervita(String tuttav){
Console.WriteLine("Tere,
"+tuttav);<
public
override double KysiKorgus(){return 1.5;}<",
t.KysiRuumala(),
v.KysiRuumala());
D:\kodu\0606\opikc#>AbstraktseKlassiUuring
Ruumalad
12 ja 282,743338823081
Ülesandeid* Lisa klassile
Kujund abstraktne meetod PohjaYmbermoot ning meetod KyljePindala.
Katseta - lisades vajalikud meetodid ka alamklassidesse.
* Loo Kujundi
alamklass
Risttahukas lisades talle vajalikud väljad kolme mõõtme
hoidmiseks ja kattes üles Kujundi abstraktsed meetodid. Katseta
mitmesuguste Risttahuka eksemplaridega.
* Koosta
mitmesuguste
Kujundite massiiv. Loo alamprogramm leidmaks massiivis
olevate kujundite ruumalade summa. Loo eraldi alamprogramm leidmaks
massiivis olevate kujundite
pindalade summa.
Meetodite asendus
Harilikult
kirjutatakse meetodite üle katmise juures ülemklassi meetodi ette
virtual ning alamklassi juurde override. Sellisel juhul alamklassi
(siinses näites Daami)
objekti puhul kasutatakse alati seda meetodit, mis tema juurde käib
- sõltumata, millisest tüübist on muutuja, mille kaudu eksemplari
poole pöördutakse. C++ võimalusi säilitades aga on jäetud ka
teine võimalus. Meetodi võib asendada nõnda, et tema kirjeldamise
ette kirjutatakse sõna new.
Sel juhul peidetakse vana meetod samuti ära. Vana meetodi saab aga
kätte juhul, kui objekti poole pöörduda ülemklassi muutujast, kus
vastav meetod vanal kujul kasutusel oli. Kui virtual/override
puhul pidid
parameetrid ja väljastustüüp samaks jääma, siis new
loob täiesti uue ja eelmisest sõltumatu meetodi.
Järgnevas näites
on ehitatud kunstlik pärilusahel. Ülemklassiks Inimene,
kes ütleb oma vanuse nõnda nagu see on. Inimesest
pärinenud Daam
võtab ilma pikemalt mõtlemata 5 aastat maha. Daami
alamklassiks olev
Beib keeldub üldse vanuse teatamisest ning eriti kaugele arenenud
KavalBeib
palub kasutajal ise tema vanust pakkuda. Sõna sealed
klassi juures näitab, et sellest klassist ei lubata enam edasi
pärida. Selline määrang aitab kompilaatoril koodi optimeerida.
Alljärgnevalt
katsetatakse, millist tüüpi muutuja kaudu millise tegeliku objekti
poole pöördumisel milline tulemus saadakse. Et omistamine on
võimalik ainult ülemklassi suunas, siis igaühe neist saab omistada
Inimese
tüüpi muutujale. Mida tase edasi, seda vähem on omistusvõimalusi.
Katsetamise
käigus antakse Beiblastele
vanuseks 17 aastat, teistele 40. Ning jälgitakse, milline meetod
millise muutuja kaudu väljakutsel käima läheb. Kõige pikem ja
keerukam lugu on Kavala Beibega. Et ta on pärimispuus kõige
kaugemal, siis teda on võimalik omistada kõikide selles puus
olevate tüüpidega muutujatele. Enese tüübi puhul küsib ta
vanuseks 19, nagu käskluses öeldud. Ka lihtsalt Beib-tüüpi
muutuja kaudu küsib ta enesele 19, sest klassi Beib
meetod YtleVanus
on virtual ning tegelikult käima läheb objekti enese ehk klassis
KavalBeib
loodud meetod.
Edasi muutub lugu
keerulisemaks. Daami-muutujast
välja kutsutav Kavala
Beibe vanus tuleb 12, sest ta lahutab aastad
maha nagu
Daamile kohane. Ning ka hariliku inimese kaudu tuleb 12,
sest virtual-piiritleja
kaudu võetakse käsklus võimalikult objekti enese lähedalt.
using
System;<
public
override void YtleVanus(){
Console.WriteLine("Minu
vanus on "+(vanus-5)+" aastat"); <
new
public virtual void YtleVanus(){
Console.WriteLine("Minu
vanus pole sinu asi, vot!");<
public
override void YtleVanus(){
Console.WriteLine("
Arva?", vanus+2);<<
//value on sisendväärtuse nimi<<
return
(string)esinemised[kuupaev];<
public
int Minut(){return minut;}
public
void tryki(){
Console.WriteLine(",
tund, minut);
public
static Kellaaeg operator +(Kellaaeg k1, Kellaaeg k2){
return
new Kellaaeg(k1.tund+k2.Tund(), k1.minut+k2.Minut());<
public
int Minut(){return minut;}
public
void tryki(){
Console.WriteLine(",
tund, minut);
public
static Kellaaeg operator+(Kellaaeg k1, Kellaaeg k2){
return
new Kellaaeg(k1.Tund()+k2.Tund(), k1.Minut()+k2.Minut());
public
static implicit operator int(Kellaaeg k){
return
k.Tund()*60+k.Minut();
public
static explicit operator double(Kellaaeg k){
//kohustuslik
muunduse näitamine
return
k.Tund()+k.Minut()/60.0;
public
static explicit operator Kellaaeg(int minutid){
return
new Kellaaeg(minutid/60, minutid%60);<
catch(FormatException
probleem){
Console.WriteLine("Viga
sisendandmetega: "+probleem.Message);
}
catch(OverflowException){
Console.WriteLine("Liiga
suur arv.");
}
catch(Exception){
Console.WriteLine("Tundmatu
probleem");
}catch(FormatException
probleem){
Console.WriteLine("Viga
teisendusel: "+probleem.Message);
D:\kodu\0606\opikc#>Erind4
Palun
arv:
5
Kirjutati:
5
Sugugi ei pea
leppima vaid arvuti enese antud veateadetega. Kui ikka oma programmis
paistab, et midagi läheb väga käest ära, siis on vahel kasulik
ise märku anda, et sarnaselt edasi toimida pole enam mõtet.
Näiteks, kui
arvutuse algandmed on ilmselgelt valed (kolmnurga üks
külg pikem kui teised kaks kokku), siis võib julgesti enne
arvutamist teada anda, milles asi ning heita selleteemalise erindi.
Edasi on juba vastavat koodilõiku väljakutsuva programmeerija
ülesandeks silumise käigus kindlaks teha, millest probleem tekkis
ning vastavalt edasi toimida.
Siin näites
lihtsalt keelati sajast suuremate arvude sisestus. Kui arv juhtub
liiga suur olema, heidetakse erind. Lihtsuse mõttes pole oma tüüpi
loodud, kasutatakse SystemExceptionit.
Kuigi - vähegi pikema programmi selguse huvides oleks oma tüübi
loomine kasulik. Et peaprogrammis pole SystemExceptioni
jaoks veapüünist, siis tuleb ette süsteemne veateade, mille järele
programmeerija peab juba ise edasi mõtlema, mida edasi teha.
using
System;
Console.WriteLine("Viga
teisendusel: "+probleem.Message);
D:\kodu\0606\opikc#>Erind5
Palun
arv:
789
Unhandled
Exception: System.SystemException:
Liiga suur arv
at
Erind5.LoeArv()
at
Erind5.Main(String[] arg)
Ülesandeid
* Katseta näite
"Erind2" juures, kuidas käitub programm juhul, kui ette
anda veatu arv.
* Muuda täisarvu
käsklused reaalarvu omadeks ja leia, mis kasutamisel muutus.
* Loo tsükkel,
mille abil küsitakse arvu senikaua, kuni saadakse sobiv sisend.
* Muuda näidet
"Erind5" nõnda, et see annaks peaprogrammis viisaka seletuse ka omaheidetud erindi korral.
* Loo erindeid
kasutades programm, mis suurendaks faili arv.txt sisu ühe võrra.
Kui fail puudub, või failis pole arv, siis antakse selgitusega
veateade.
* Kui failis olev
arv ületab 365, siis anna välja omapoolne erind ning püüa sellele
reageerida.
Enum
Ikka leidub
kohti, kus on võimalik teha piiratud arv valikuid . Asukoht Eestis on
ühes maakondadest. Ühissõiduk on üldjuhul rong , tramm, troll või
buss jne. Kui programmikoodis tuleb leida käitumisjuhis ühele
etteantud valikutest, siis on enum hea abivahend . Maakonna nime saab
kirjutada mitmeti. Olgu siis " Harjumaa ", või "Harju
maakond", rääkimata suurte ja väikeste tähtede ning tühikute
erisusest. Andmebaaside puhul kasutatakse üldjuhul võimalust, et ei
kirjutata inimese andmete juurde maakonna nime, vaid pannakse selle
maakonna kood. Ning selle järgi on vajadusel võimalik teisest
andmetabelist järele vaadata, millise maakonnaga siis päriselt
tegu. Midagi sarnast toimub ka enumi puhul. Ehk siis vastavas loetelus kirjeldatakse ära kõik võimalikud väärtused. Ning
hiljem programmi sees pole võimalik enam vastavat nimetust valesti
kirjutada ilma, et kood kompileerimata jääks. Sedasi on võimalik
vältida vigu, mis muidu üllatavatel hetkedel võiksid avalduda.
Tüüpiliseks kasutuskohaks on näiteks alamprogrammi parameetrid,
kus enumi abil määratakse, kuidas just sel korral vastavate
andmetega tuleb käituda. Järgnevas näites siis tuuakse tugevuse
kohta kolm konstanti: tumm, ühekordne ja mitmekordne. Ning praegusel
juhul alamprogrammis esimese variandi puhul jäetakse etteantud tekst
sootuks trükkimata. Teisel juhul trükitakse ühe korra ning
viimasel juhul mitu korda. Kui aga ühekordne kirjutatuks nõrga
g-ga, siis jäänuks kood kompileerimata. Pealtnäha
iseenesestmõistetav. Aga kui enumi asemel olnuks kasutatud stringi,
siis just sellised vead on kerged tulema.
using
System;<;<",
ht["Kati"]);
Kontrollitakse,
kas Kati on nimede hulgas olemas. Kui jah, siis trükitakse ta hinne.
ht["Sass"]=((int)ht["Sass"])-1;
Sassi hinnet
alandatakse ühe võrra.
ht.Remove("Mati");
Mati eemaldatakse
nimekirjast.
Tahtes kõik
andmed kätte saada, aitab jälle enumeraator, ainult et igal
enumeraatori elemendil on võti ja väärtus. Siin trükitakse nad
lihtsalt välja, aga eks igaüks tea ise paremini, mida tal oma
programmis nendega kõige mõistlikum teha on.
IDictionaryEnumerator
enumr=ht.GetEnumerator();
while(enumr.MoveNext()){
string
eesnimi=enumr.Key as string;
int
hinne=(int)enumr.Value;
Console.WriteLine(", eesnimi, hinne);
Ning kogu näide
tervikuna.
using
System;
using
System.Collections;<",
ht["Kati"]);
ht["Sass"]=((int)ht["Sass"])-1;
ht.Remove("Mati");
IDictionaryEnumerator
enumr=ht.GetEnumerator();
while(enumr.MoveNext()){
string
eesnimi=enumr.Key as string;
int
hinne=(int)enumr.Value;
Console.WriteLine(", eesnimi, hinne);
D:\kodu\0606\dotnet>Kollektsioon4
5
Kati:
5
Juku:
3
Sass:
3
Ülesandeid
* Küsi
kasutajalt arve, kuni ta sisestab nulli. Salvesta ArrayListi.
Väljasta need arvud tagurpidises järjekorras.
* Proovi eelmine ülesanne lahendada LinkedListi abil. Omadus Last annab loetelu viimase elemendi, RemoveLast() kustutab viimase.
* Loe
tekstifailist arvud, väljasta nad sorteerituna teise tekstifaili.
* Loe
tekstifailist arvud. Teise tekstifaili väljasta, mitu korda iga arv
esines.
Mallid
Objektorienteeritus
võimaldab alamklasside eksemplare omistada ülemklassi tüüpi
muutujatele. Nõnda saab lahendada enamiku olukordi, kus koodilt
nõutakse paindlikkust ning võimet veidi erinevaid objekte ühiselt
hoida või käidelda. Kus pole võimalik objekte omistada muidu
pärimispuu järgi, seal tuleb appi teadmine, et kõik pärineb
ühisest ülemklassist System.Object. Või siis saab eri
pärimispuudest tulnud klasside ühiseid käsklusi kasutada liideste
abil. Nii et kõik vajalik peaks sellega olemas olema.
Ometigi on C#
juurde kaasa võetud C++ist mallid ehk šabloonid ehk geneerilisus.
Ehk siis võimalus kasutatavaid andmetüüpe määrata pärast kasutatava klassi koodi enese valmiskirjutamist. Sellega kaasneb
vähemasti kaks head omadust:
* Kui andmetüüp
on täpselt määratud, siis on karta vähem valest omistamisest
tingitud vigu.
* Kompilaatoril
on võimalik koodi optimeerida konkreetse andmetüübi omadustest
lähtudes ning programmi töö käigus ei pea kulutama aega tegeliku
andmetüübi kontrollimisele.
Võimalust
kasutatakse tihti geneeriliste andmekollektsioonide juures. Kui muidu
oli hoiustatud andmete kohta teada ainult, et need on klassi Object
järglased (ehk siis nagu polnudki tüübi kohta suurt midagi teada),
siis geneerilise Listi puhul saab määrata näiteks, et loetelus
esinevad elemendid on täisarvud. Ning selle põhjal on edaspidises
kasutuses teada, et vastavast loetelust välja võetavad andmed on ka
sama tüüpi. Nagu järgnevast näitest näha, siis ka loetelu
läbimiseks mõeldud enumeraatorile tuleb sama tüüp määrata.
Andmestruktuuri
ülesehituse eripärast lähtudes on LinkedListi läbikäimine
enumeraatori abil tunduvalt ökonoomsem kui järjestikuste andmete
küsimine elemendi järjekorranumbri järgi. Konkreetse
järjekorranumbriga kohani jõudmiseks tuleb järjekorranumbri puhul
enne kõik elemendid listisiseselt läbi jalutada. Enumeraator aga
mõistab andmeid ilusti järjest võtta.
using
System;
using
System.Collections.Generic;< <<<; "+
"DBQ=d:\\kodu\\0606\\dotnet\\proovibaas2.mdb;
"+
"Trusted_Connection=yes";
string lause="SELECT mark
FROM autod";
OdbcConnection cn=new
OdbcConnection(constr);
cn.Open();
OdbcCommand cm = new
OdbcCommand(lause, cn);
OdbcDataReader
reader=cm.ExecuteReader();
while(reader.Read()){
Console.WriteLine(reader.GetString(0));
cn.Close();
Kui aga tegemist
pole Accessiga, vaid mõne muu andmebaasikeskkonnaga, mis aga
sellegipoolest on Control Paneli kaudu ODBC alt kättesaadav, siis ka
sealtkaudu saab oma andmetele ligi. Olgu näiteks olemas juba toimiv
veebibaas PHP ja MySQLi abil – kuhu aga tahetakse ka kohalikus
arvutis toimiva programmi kaudu pilku peale visata . Tehes see algne
baas ODBC kaudu nähtavaks nime all näiteks proovibaas2, näeks
sidepidamisprogramm välja nagu järgnevalt. Tasub tähele panna, et
võrreldes SQL-serveriga on kasutatavateks objektiklassideks
OdbcConnection
ja OdbcCommand.
Aga andmetega ümber käiakse ikka samamoodi.
using System;
using System.Data.Odbc;<
Ja ongi kogu
näide, mida võib edaspidi sarnaste rakenduste loomisel aluseks
võtta.
using
System;<;
IEnumerable
query = from s in names
where
s.Length == 5
orderby
s
select
s.ToUpper();
foreach
(string item in query)
Console.WriteLine(item);
Tulemuseks on:
BURKE
DAVID
FRANK
LINQ mõistmiseks
tuleks esmalt vaadelda programmi esimest lauset:
IEnumerable
query = from s in names
where
s.Length == 5
orderby
s
select
s.ToUpper();
Kohalik muutuja
Query väärtustatakse päringu avalisega. Päringuavaldis võtab
andmeid ühest või mitmest andmeallikast ning võimaldab sooritada mitmeid operatsioone. Antud päring kasutab kolme standardset operaatorit : Where, OrderBy ja Select.
Seega võiks seda
päringut lugeda järgmiselt: loome loendatava teksti sisaldava
massiivi Query, valides andmed tekstimassiivist names kus teksti
pikkuseks on 5 märki ning sorteerime tulemuse tähestikuliselt ning
tulemusena näitame sobivaid tekstiväärtusi suurte tähtedega.
LINQ päringuid
saab teha kõigi loendatavate kollektsioonide ja massiivide peal.
Kõik LINQ päringud koosnevad kolmest tegevusest:
- Andmeallika tekitamine
- Päringu loomine
- Päringu käivitamine
using
System;
using
System.Linq;
using
System.Collections.Generic;<;
//
2. Päringu loomine.
//
numQuery
tekitatakse IEnumerable
tüüpi
var
numQuery
=
from
num
in
numbers
where
(num
% 2) == 0
select
num;
//
3. Päringu käivitamine.
foreach
(int
num
in
numQuery)
Console.Write(
", num);
Põhikonstruktsioonide näited
Lühim
tervitav programm
using
System;<
else {
Console.WriteLine("Mind
pole homme kodus.");
Kordus
while abil
int
nr=1;
while(nr
Kõik kommentaarid