You are on page 1of 58

OSNOVE

C#

MARKO PRIVONIK LJUBLJANA, NOVEMBER 2003

OSNOVE C#

KAZALO VSEBINE
1 UVOD 3 1.1 Komu je knjiga namenjena? 3 1.2 Kaj je platforma .NET? 3 1.2.1 Skupno izvajalno okolje (CLR) 4 1.2.2 Knjinica razredov .NET 5 2 OSNOVE C# 6 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.5 2.6 2.7 2.7.1 2.8 2.8.1 2.8.2 2.8.3 3 Prvi program v C# 6 Imenski prostori 6 Razredi in predmeti 7 Vhod in izhod 7 Komentarji 8 Prevajanje in izvajanje 8 Oblika in izgled 8 Osnovni gradniki jezika 10 Imena 10 Kljune besede 11 Konstantne vrednosti 11 Operatorji in loila 14 Komentarji 15 Podatkovni tipi 15 Vrednostni tipi 17 Sklicni tipi 20 Spremenljivke in parametri 24 Spremenljivke 24 Parametri 26 Izrazi in operatorji 29 Programski stavki 30 Imenski prostori 38 Uporaba imenskih prostorov 39 Prevedi in izvedi 40 Prevajanje enostavnega programa 40 Doloanje izhodnega formata pri prevajanju 41 Vkljuevanje knjinic 41

RAZREDI IN PREDMETI 43 3.1 Osnove predmetno usmerjenega programiranja 43 3.1.1 Dedovanje 43 3.1.2 Enkapsulacija 44 3.1.3 Polimorfizem 46 3.2 lani razreda 46 3.2.1 lanske konstante in spremenljivke 46 3.2.2 Metode 47 3.2.3 Lastnosti 47 3.2.4 Indekserji 48 3.2.5 Operatorji 50 3.2.6 Dogodki 50 3.2.7 Konstruktorji 50 3.2.8 Destruktor 51

OSNOVE C#

4 4.1 4.2 4.3 4.4 4.5 4.6 5

IZBRANA DODATNA POGLAVJA 52 Rokovanje z izjemami 52 Boxing in unboxing 53 Pretvorbe med tipi 53 Smetar 54 Atributi 55 XML dokumentacijski komentarji 55 LITERATURA 56

OSNOVE C#

1 UVOD

C# je moderen in atraktiven programski jezik nove generacije. Odlikujejo ga predmetna usmerjenost, enostavnost ter varnost programiranja. Kljub svoji enostavnosti je C# moan jezik, primeren tudi za razvoj najzahtevneje programske opreme. C# je razvojni potomec programskih jezikov C, C++ in Java. Kljub temu, da ne skriva svojega porekla, je C# odlino opremljen za sodobne in bodoe izzive, ki jih predstavljajo sodobni trendi na podroju informacijskih tehnologij.

1.1 Komu je knjiga namenjena?


Ta knjiga je primerna za bralce, ki niso popolni zaetniki v programiranju in e poznajo osnovne principe programiranja. Knjiga naj slui kot vodnik po programskem jeziku C# za bralce, ki znajo vsaj za silo programirati v kakem drugem programskem jeziku. Knjiga pa bo prila prav tudi tistim veim programerjem, ki bi radi na hitro spoznali novosti in posebnosti tega sodobnega programskega jezika.

1.2 O programskem jeziku C#


Programski jezik C# je nastal v okviru razvoja iroko in ambiciozno zastavljenega projekta .NET, ki si ga je zastavil Microsoft v poznih devedesetih letih. Cilj tega projekta je bil nadomestiti okorno komponentno usmerjeno tehnologijo COM, ki je vedno teje zadovoljevala zahteve pri razvoju programske opreme. .NET predstavlja novo razvojno platformo, ki bo kos izzivom razvoja sodobne programske opreme, v kateri igra jezik C# vlogo sodobnega in s preteklostjo neobremenjenega predmetno usmerjenega programskega jezika. Pri nartovanju jezika C# so se pri Microsoftu zgledovali predvsem po programskem jeziku Java. Kljub temu pa je C# svojsten jezik, ki se od Jave razlikuje v marsikateri pomembni toki. Glavni nartovalec jezika C# je Anders Hejlsberg, ki je med drugim razvil tudi programski jezik Delphi. C# je standardiziran programski jezik. Najprej je bil leta 2001 sprejet kot standard v okviru organizacije ECMA, nato pa je leta 2003 postal tudi ISO standard. Kljub temu pa se razvoj jezika C# e vedno aktivno nadaljuje.

OSNOVE C#

1.3 Okolje programskega jezika C#


Programski jezik C# je tesno povezan z Ogrodjem .NET (angl. .NET Framework), brez katerega programov pisanih v C# ne moremo poganjati. Ogrodje .NET zdruuje dve pomembni komponenti: skupno izvajalno okolje (angl. common language runtime CLR) in knjinico razredov.

Ogrodje .NET KNJINICA OSTALIH PODPORNIH RAZREDOV KNJINICA OSNOVNIH RAZREDOV SKUPNO IZVAJALNO OKOLJE OPERACIJSKI SISTEM

Slika 1.1: Ogrodje .NET. Skupno izvajalno okolje poskrbi za izvajanje prevedene programske kode, knjinica razredov pa vsebuje bogato zbirko razredov, ki jih programer lahko uporabi pri razvoju reitve. Programerji potrebujejo poleg Ogrodja .NET e vsaj prevajalnik izvorne programske kode. Ta je skupaj z ostalimi razvojnimi orodji, dokumentacijo in primeri vsebovan v okolju za razvoj programske opreme za Ogrodje .NET (.NET Framework Software Development Kit - SDK). Razvojno okolje je na voljo zastonj na spletnih straneh podjetja Microsoft. V zadnjem asu so se zaele pojavljati tudi alternativne razliice okolja za poganjanje in razvoj programov v C#-u, ki veinoma temeljijo na naelu odprte kode. Tako nam okolje, ki je bilo razvito v okviru projekta Mono, nudi prevajalnik za jezik C#, skupno izvajalno okolje in knjinico razredov. Medtem, ko sta originalno Ogrodje .NET in pripadajoe okolje za razvoj programske opreme namenjena operacijskemu sistemu Windows, lahko uporabljamo Mono tudi na operacijskem sistemu Linux, v bodonosti pa tudi na nekaterih drugih platformah.

1.3.1 Skupno izvajalno okolje (CLR)


Skupno izvajalno okolje izvaja programsko kodo, ki temelji na zbirnem jeziku CIL (angl. Common Intermediate Language). Programska koda CIL je rezultat prevajanja kateregakoli od mnogih jezikov, ki temeljijo na Ogrodju .NET. Pred samim izvajanjem je zato potrebno programe pisane za Ogrodje .NET najprej z ustreznim prevajalnikom prevesti v programsko kodo CIL. Ob asu izvajanja skupno izvajalno okolje sproti in dinamino prevaja programsko kodo CIL v strojno kodo primerno za platformo na kateri poteka izvajanje programa. Tako dobljeno strojno kodo nato izvede centralna procesna enota. Programska koda CIL se torej

OSNOVE C#

praviloma ne interpretira, temve se v okviru izvajalnega okolja prevaja. Programski kodi, ki je namenjena izvajanju v skupnem izvajalnem okolju, pravimo upravljana programska koda (angl. managed code). Skupno izvajalno okolje predstavlja temelj platforme .NET saj omogoa: nadzorovano izvajanje lokalne ali oddaljene programske kode za vso druino jezikov .NET, varno in robustno izvajanje programske kode, vkljuno s kodo z neznanim poreklom, reevanje opreme, konfliktov zaradi neskladnosti nameenih razliic programske

upravljanje s pomnilnikom in upravljanje niti.

Natete lastnosti skupnega izvajalnega okolja omogoajo enostavno prenosljivost programov, pisanih v programskih jezikih za ogrodje .NET, med razlinimi platformami. Preveden program v obliki CIL lahko v nespremenjeni obliki izvajamo na vseh platformah na katerih tee skupno izvajalno okolje in so podprte s potrebno knjinico razredov. Po drugi strani pa nam opisan koncept skupnega izvajalnega okolja omogoa enostavno in uinkovito interoperabilnost med programsko kodo pisano v razlinih programskih jezikih.

1.3.2 Knjinica razredov .NET


Knjinica razredov .NET je obirna in vsestranska predmetno usmerjena zbirka razredov, vmesnikov in vrednostnih tipov, ki jih lahko uporabimo pri razvoju raznovrstnih aplikacij, vse od tradicionalnih do najsodobnejih spletnih in XML aplikacij. Tipi, ki jih vsebuje knjinica razredov .NET, predstavljajo osnovo na kateri lahko gradimo aplikacije in programske gradnike. Knjinica razredov .NET omogoa razvoj aplikacij, ki temeljijo na standardnih oblikah in nainih komunikacije in so tako povezljive z ostalo programsko opremo.

OSNOVE C#

2 OSNOVE C#

2.1 Prvi program v C#


Preden se podrobneje seznanimo s programskim jezikom C#, si najprej oglejmo kratek program, napisan v tem programskem jeziku, ki v ukaznem oknu izpie niz Pozdravljen svet!. using System; class MojPrviRazred { static void Main(string[] args) { Console.WriteLine("Pozdravljen svet!"); // izpisali smo pozdrav svetu } } Pomembni pojmi, ki jih lahko na primeru tega preprostega programa na kratko spoznamo so: imenski prostori razredi in predmeti vhod in izhod komentarji prevajanje in izvajanje

2.1.1 Imenski prostori


Na enostaven program definira nov razred, ki za svoje delovanje uporablja e pripravljen razred z imenom Console. Knjinica pripravljenih razredov (in drugih tipov) je zaradi svoje obirnosti organizirana v hierarhino strukturo imenskih prostorov, do posameznih razredov pa lahko pridemo z navedbo vseh potrebnih

OSNOVE C#

imenskih prostorov v katerih je razred vsebovan in imena samega razreda. Razred Console je tako vkljuen v imenski prostor System, naslavljamo pa ga z dolgim imenom System.Console. Direktiva using omogoa uporabo razredov iz nekega imenskega prostora brez navedbe imenskega prostora. Prva vrstica programa: using System; nam torej omogoa enostavno uporabo tipov deklariranih v imenskem prostoru System, saj jih lahko v programu uporabljamo samo z navedbo imena tipa brez navedbe imenskega prostora (na primer razred Console). Imenske prostore lahko definiramo tudi sami in s tem smiselno organiziramo in uredimo lastno programsko kodo.

2.1.2 Razredi in predmeti


Osnovni del naega programa predstavlja definicija razreda. Razred definiramo s kljuno besedo class, ki ji sledi ime definiranega razreda in telo razreda vsebovano med zavitima oklepajema: class MojPrviRazred { <telo razreda> } Na razred vsebuje le eno metodo (metodo z imenom Main), ki je podana z naslednjo definicijo: static void Main(string[] args) { <telo metode> } Metoda Main je definirana s pridevnikoma static in void . Pridevnik static doloa, da je metoda statini lan razreda in jo je zato mogoe uporabiti tudi brez izvoda razreda. Metoda Main je vstopna toka naega programa. Ker na samem zaetku izvajanja programa nimamo e nobenega izvoda razredov, mora biti metoda Main statina metoda. Pridevnik void oznauje, da metoda ne vraa nobene vrednosti. Desno od imena metode se nahaja deklaracija parametrov. Naa metoda sprejme en parameter tipa polje nizov (polje predmetov tipa string), ki smo ga poimenovali args. Posamezni nizi v polju predstavljajo argumente ukazne vrstice ob zagonu naega programa.

2.1.3 Vhod in izhod


Telo metode sestavlja le en stavek: Console.WriteLine("Pozdravljen svet!");

OSNOVE C#

Ta stavek poklie statino metodo WriteLine, ki pripada razredu Console. Ta razred pripada knjinici razredov .NET in nudi osnovno podporo programom, ki berejo znake iz ukaznega okna ali vanj piejo. V naem primeru elimo v ukazno okno izpisati niz Pozdravljen svet!. Poleg razreda Console nam knjinica razredov nudi celo mnoico razredov za razlino delo z vhodom in/ali izhodom.

2.1.4 Komentarji
V naslednji vrstici se nahaja komentar: // izpisali smo pozdrav svetu Znaka // oznaujeta zaetek komentarja, ki traja do konca vrstice. Blok besedila lahko zakomentiramo tudi s parom /* in */, ki oznaujeta zaetek in konec komentarja: /* Moj prvi program. Program izpie niz "Pozdravljen svet!". */

2.1.5 Prevajanje in izvajanje


Na program lahko napiemo in prevedemo v okviru razvojnega okolja Visual Studio ali pa kar s splonim urejevalnikom besedila in neposrednim zagonom prevajalnika iz ukazne vrstice. V drugem primeru je dovolj, da imamo na raunalniku nameeno le brezplano okolje za razvoj programske opreme za Ogrodje .NET (.Net Framework SDK) in ne celotnega razvojnega okolja Visual Studio. Na tem mestu si oglejmo to monost. S pomojo poljubnega urejevalnika besedil (na primer notepad.exe) ustvarimo datoteko, ki vsebuje izvorno kodo programa. Ker datoteka predstavlja program pisan v programskem jeziku C#, jo shranimo pod poljubnim imenom s podaljkom .cs. Predpostavimo, da se datoteka imenuje Pozdravljen.cs. Program prevedemo s prevajalnikom za programski jezik C#. Prevajalnik zaenemo na naslednji nain: csc Pozdravljen.cs e prevajalnik ne naleti na nobeno napako, ustvari datoteko Pozdravljen.exe. Na tem mestu lahko zaenemo prevedeni program na naslednji nain: Pozdravljen

2.1.6 Oblika in izgled


C# je po obliki in izgledu podoben Javi. V tej lui sta njegovi glavni znailnosti: deklaracija in definicija tipov (in njegovih lanov) se nahajata na enem mestu, vsa efektivna programska koda pripada definiciji katerega od definiranih tipov in ne more obstajati samostojno izven definicij tipov.

Program torej predstavlja seznam definicij razredov ali njegovih variacij (strukture,

OSNOVE C#

vmesniki ...). C# v mnogoem izboljuje mnoge javanske nerodnosti in pomanjkljivosti. Javanskim temeljem pa dodaja nekatere C++/C-jevske primesi, kot so na primer natevni in kazalni podatkovni tip ter pogojno prevajanje. Izvorni program napisan v programskem jeziku C# je formalno pravzaprav kar definicija globalnega imenskega prostora. Definicija imenskega prostora je sestavljena iz definicij njegovih lanov, ti pa so: razredi strukture vmesniki natevni tipi delegati imenski prostori

To pomeni, da izvorno datoteko v C# sestavljajo definicije razredov, struktur, vmesnikov, natevnih tipov, delegatov in imenskih prostorov. V nadaljevanju je prikazan primer splone oblike programa z vsemi natetimi programskimi elementi. delegate void Callback(int data); namespace FRI.Teaj { interface IPonastavljiv { void ponastavi(); } struct Toka : IPonastavljiv { public int x,y; Color color; public void ponastavi() { x = y = 0; } } class MojPrviRazred { static void Main() { System.Console.WriteLine("ivjo svet!"); }

OSNOVE C#

} enum Color {Bela, Rdea, Modra, Zelena, rna}; }

2.2 Osnovni gradniki programa


Osnovni gradniki programa so najosnovneji elementi (angl. tokens), na katere prevajalnik za nek programski jezik razdeli izvorno programsko kodo. Ta razdelitev se izvede v prvem koraku prevajanja, ki se imenuje leksikalna analiza. Tako kot veina sorodnih programskih jezikov, pozna tudi C# naslednje vrste osnovnih elementov: imena, kljune besede, konstantne vrednosti, operatorje in loila. Prevajalnik za jezik C# obravnava vse znake izvorne programske kode po standardu Unicode in pri tem razlikuje med malimi in velikimi rkami.

2.2.1 Imena
Imena (angl. identifiers) enolino oznaujejo razline elemente programa, kot so na primer spremenljivke, razredi in metode. Zaeljeno je, da je izbira imena smiselna in skladna z vlogo elementa v programu. Pravila za imena ustrezajo priporoilom standarda "Unicode 3.0 - Technical Report 15 - Annex 7" z nekaj izjemami. Na enostaven nain jih lahko opiemo z naslednjimi pravili: Ime se lahko zane z znakom abecede, s podrtajem (_), z znakom @ ali z unicodovo ubeno kodo, ki ustreza tem kategorijam znakov. Ostali znaki imena so lahko znaki abecede, numerini znaki, podrtaj (_) ali unicodova ubena koda, ki ustreza tem kategorijam znakov (prav tako so dovoljeni tudi znaki iz unicode razredov Mn, Mc, Pc ali Cf). Ime sme biti enako kateri od kljunih besed le, e ji na zaetek dodamo znak @. V tem primeru znak @ kljub temu ni del imena.

Tretje pravilo, ki glede na sorodne programske jezike predstavlja novost, je pomembno zaradi jezikovne interoperabilnosti Ogrodja .NET. Razlini programski jeziki znotraj Ogrodja .NET imajo razline kljune besede in zato se lahko zgodi, da je ime nekega razreda v programski kodi napisani v enem izmed programskih jezikov enako kljuni besedi nekega drugega programskega jezika. Opisano pravilo nam omogoa uporabo takih razredov tudi v programski kodi napisani v drugem programskem jeziku. Primeri veljavnih imen so: Oseba @class _token inica \u0043sharp

Naslednje besede ne predstavljajo veljavnih imen: 6erica goto

10

OSNOVE C#

\u0027beseda

2.2.2 Kljune besede


Kljune besede (angl. keywords) so imena, ki imajo v jeziku C# rezerviran pomen in so del samega programskega jezika. Teh besed zato ne smemo uporabiti kot navadna imena (razen v kombinaciji z znakom @). Programski jezik C# pozna 77 kljunih besed. Nekatere kljune besede lahko nastopajo v ve vlogah. Vse kljune besede programskega jezika C# so navedene in grupirane po skupinah glede na njihovo uporabo v tabeli 2.1. SKUPINA tipi KLJUNE BESEDE struct enum class interface delegate sbyte byte char short ushort int uint long ulong float double decimal bool object string void public private internal protected abstract const event extern override readonly sealed static unsafe virtual volatile if else switch case do for foreach in while break continue default goto return throw try-catch try-finally checked unchecked fixed lock params ref out namespace using as is new sizeof typeof true false stackalloc checked unchecked explicit implicit operator this base null true false

pridevniki

stavki

parametri metod imenski prostori operatorji pretvorba dostop konstante

Tabela 2.1: Kljune besede programskega jezika C#.

2.2.3 Konstantne vrednosti


Konstantne vrednosti (angl. literals) so predstavitve vrednosti, ki nastopajo v izvorni kodi. Z njimi lahko zapiemo vrednosti za podatkovne tipe bool, int, uint, long ulong, float, double, decimal, char, string ter vrednost null za sklicne podatkovne tipe. Oglejmo si dva primera uporabe konstantnih vrednosti v programu. System.Console.WriteLine("Hello World");

11

OSNOVE C#

double irina = 12.3; V prvem primeru je konstantna vrednost niz "Hello World", v drugem pa numerina vrednost tipa double 12.3. 2.2.3.1 Logine vrednosti Konstantni vrednosti za logine vrednosti sta kljuni besedi true in false in sta tipa bool. 2.2.3.2 Cela tevila Celotevilne konstantne vrednosti uporabljamo za zapis tipov int, uint, long in ulong. Vrednosti lahko zapiemo v desetiki ali estnajstiki obliki. Zapis konstantne vrednosti v estnajstiki obliki se mora zaeti z zaporedjem 0x ali 0X, ki mu sledi zapis same vrednosti z zaporedjem veljavnih znakov (0-9, a-f ali A-F). Celo tevilo 123 lahko torej zapiemo tudi kot 0x7b. Dodeljeni podatkovni tip celotevilne konstantne vrednosti bo prvi tip iz seznama int, uint, long, ulong, ki lahko predstavlja vrednost. Dodeljeni podatkovni tip lahko doloimo tudi eksplicitno s priponami: e je pripona U ali u bo dodeljeni tip prvi tip iz seznama uint, ulong, ki lahko predstavlja vrednost. e je pripona L ali l bo dodeljeni tip prvi tip iz seznama long, ulong, ki lahko predstavlja vrednost. e je pripona UL, Ul, uL, ul, LU, Lu, lU ali lu bo dodeljeni tip ulong. Celotevilna konstantna vrednost 123 bo tako tipa int, medtem ko bo celotevilna konstantna vrednost 123UL tipa ulong.

2.2.3.3 Realna tevila Realne konstantne vrednosti uporabljamo za zapis tipov float, double in decimal. Realna konstantna vrednost mora ustrezati vsaj enemu izmed naslednjih pogojev: Vsebovati mora decimalno loilo, ki je pika (.). Primera take realne konstantne vrednosti sta zapisa 1.0 ali .01. Vsebovati mora eksponentni del zapisa, ki ga doloata znak e ali E ter eksponent. Primera take realne konstantne vrednosti sta zapisa 1E10 in 123E-2. Vsebovati mora eno izmed pripon F f D d M m, ki doloajo realno konstantno vrednost. Primera take realne konstantne vrednosti sta zapisa 1F in 123.456M.

Dodeljeni tip realne konstantne vrednosti brez pripone bo double. Dodeljeni podatkovni tip lahko doloimo tudi eksplicitno s priponami: e je pripona F ali f bo dodeljeni tip float. e je pripona D ali d bo dodeljeni tip double. e je pripona M ali m bo dodeljeni tip decimal.

2.2.3.4 Znakovne vrednosti Znakovno konstantno vrednost uporabljamo za zapis tipa char. Tako vrednost zapiemo med enojne narekovaje, kot na primer pri 'a'. Med narekovaji se lahko nahaja katerikoli znak razen enojnega narekovaja ('), obrnjene poevnice (\) ali

12

OSNOVE C#

znaka za prehod v novo vrsto. Prav tako se lahko med narekovaji nahaja navadno ubeno zaporedje, estnajstiko ubeno zaporedje ali ubeno zaporedje unicode. Vsa dovoljena ubena zaporedja so navedena v tabeli 2.2. UBENO ZAPOREDJE \' \" \\ \0 \a \b \f \n \r IME ZNAKA enojni narekovaj dvojni narekovaj obrnjena poevnica Null Alert povratek (backspace) nov list (form feed) nova vrsta (new line) povratek na zaetek vrste (carriage return) vodoravni zamik (horizontal tab) navpini zamik (vertical tab) estnajstiko ubeno zaporedje (d je estnajstika tevka) KODIRANJE UNICODE 0x0027 0x0022 0x005C 0x0000 0x0007 0x0008 0x000C 0x000A 0x000D 0x0009 0x000B 0x000d 0x00dd 0x0ddd 0xdddd 0xdddd

\t \v \xd \xdd \xddd \xdddd \udddd \Udddd

ubeno zaporedje Unicode (d je estnajstika tevka)

Tabela 2.2: Dovoljena ubena zaporedja za znakovne vrednosti. 2.2.3.5 Nizi znakov Konstantna vrednost za niz uporabljamo za zapis tipa string. C# podpira dva naina zapisa konstantnih vrednosti za niz: obiajni in dobesedni nain. Obiajna konstantna vrednost za niz je zapisana z ni ali ve znaki, ki so objeti z dvojnima narekovajema ("). Veljavni so vsi znaki in ubena zaporedja, ki so veljavne znakovne konstantne vrednosti (glej tabelo 2.2) razen samega znaka za dvojni narekovaj ("). Dobesedna konstantna vrednost za niz je prav tako zapisana z ni ali ve znaki, ki so objeti z dvojnima narekovajema, vendar s predpono @. Veljavni znaki so vsi znaki razen znaka za dvojni narekovaj ("). V tem nainu so vsi znaki med dvojnima narekovajema tolmaeni dobesedno, zato v dobesednem nainu ne moremo

13

OSNOVE C#

uporabljati ubenih zaporedij. Edina izjema je zaporedje "", ki se tolmai kot znak ". Dobesedna konstantna vrednost se lahko razteza tudi preko ve vrstic. Oglejmo si tiri primere veljavnih znakovnih nizov: string pot1 = "c:\\program files"; string pot2 = @"c:\program files"; string seznam1 = "Eva\nMojca\nMiha" string seznam2 = @"Eva Mojca Miha"; V zgornjih primerih predstavljata spremenljivki pot1 in pot2 isti niz. Prav tako to velja tudi za spremenljivki seznam1 in seznam2. Enake konstantne vrednosti za niz , ki se nahajajo v istem programskem zbiru, se vedno nanaajo na isti predmet. 2.2.3.6 Nevzpostavljen sklic Konstantna vrednost za nevzpostavljen sklic je kljuna beseda null in je privzeta vrednost za sklicne podatkovne tipe.

2.2.4 Operatorji in loila


Operatorje uporabljamo v izrazih za opis elene operacije nad operandi, ko elimo na podlagi operandov izraunati novo vrednost. Loila uporabljamo za grupiranje in loevanje. Operatorji: true false new is sizeof typeof checked unchecked spadajo med kljune besede. Med loila ali operatorje, ki niso istoasno tudi kljune besede sodijo: { + = == |= } < != ^= [ * > ] / ? <= ( % ++ >= ) & . | -+= , ^ && -= : ! || *= ; ~ << /= >> %= &=

<<= >>= ->

Operatorje bomo podrobneje obravnavali v poglavju o operatorjih in izrazih.

14

OSNOVE C#

2.2.5 Komentarji
Komentarji ne sodijo med osnovne elemente jezika, saj ne vplivajo na rezultat prevajanja v izvrno kodo. Kljub temu pa so pomembni, saj pomagajo programerju pri oblikovanju berljivega in jasnega izvornega programa. C# podpira tri vrste komentarjev: enovrstine, omejene in dokumentacijske. Enovrstini komentarji se zanejo z znakoma // in se nadaljujejo do konca vrstice. Omejeni komentarji se zanejo z znakoma /* in konajo z znakoma */. Omejeni komentarji se lahko raztezajo preko ve vrstic. Dokumentacijski komentarji sluijo avtomatski izdelavi programske dokumentacije in so po vlogi podobni Javanskim dokumentacijskim komentarjem. Z dokumentacijskimi komentarji lahko opremimo definicije tipov in njihovih lanov ter definicije imenskih prostorov. Dokumentacijski komentarji se morajo v izvorni kodi nahajati pred definicijami elementov, ki jih dokumentiramo. Dokumentacijski komentarji se zanejo z zaporedjem znakov ///, ki jim sledi dokumentacijska vsebina v obliki XML. Tako napisano dokumentacijo lahko pridobimo iz izvorne kode s prevajanjem ob uporabi stikala /doc. Primer omejenega, dokumentacijskega in enovrstinega komentarja: /* to je omejeni

komentar */ /// <summary> /// Dokumentacijski komentar za razred MojPrviRazred. /// </summary> class MojPrviRazred { /// <summary> Kratek opis metode Main.</summary> /// <returns> Metoda Main ne vraa ni.</returns> static void Main(string[] args) { // tole pa je enovrstini komentar Console.WriteLine("Pozdravljen svet!"); } }

2.3 Podatkovni tipi


Podatkovni tip predstavlja in doloa vrsto, organizacijo in format zapisa vsebovanih podatkov. Poenostavljeno lahko reemo, da tip doloa vrsto podatkov, ki jih hrani neka spremenljivka. Na program napisan v programskem jeziku C# lahko gledamo kot na zbirko tipov, saj je vsa efektivna programska koda vsebovana v definicijah tipov. Toneje lahko opredelimo program napisan v jeziku C# kot zbirko definicij novih podatkovnih tipov, ki so organizirani v imenske prostore. Pojem podatkovnega tipa ima torej v

15

OSNOVE C#

jeziku C# osrednjo vlogo. Pri definiciji novih podatkovnih tipov se lahko programer nasloni na obstojee tipe. Ti sodijo v eno od treh kategorij: mnoica tipov, ki so definiranih na ravni jezika in jim pravimo vgrajeni tipi (int, byte, char, string, object ...); mnoica tipov, ki so definirani v okviru knjinice razredov Ogrodja .NET (FileStream, Stack, Socket, Thread ...) ali katere druge knjinice; mnoica tipov, ki so definirani v okviru iste programske kode.

2.3.1 Osnovni vrsti podatkovnih tipov: vrednostni in sklicni tipi


C# pozna dve osnovni vrsti podatkovnih tipov, ki se med seboj razlikujeta v nainu kako so shranjene vrednosti. Vsi tipi v programski kodi napisani v jeziku C# (slika 2.2) pripadajo eni ali drugi osnovni vrsti podatkovnih tipov: vrednostni tipi (angl. value types) sklicni tipi (angl. reference types)

Spremenljivka vrednostnega tipa hrani dejansko vrednost, ki pripada spremenljivki. Spremenljivka sklicnega tipa hrani sklic (referenco) na vrednost, ki pripada spremenljivki. Vrednostni tipi torej omogoajo neposredno hranjenje vrednosti, sklicni tipi pa posredno hranjenje preko sklica, ki je predstavljen z naslovom podatkov (slika 2.1).

Tipi

Vrednostni tipi

Sklicni tipi

Strukturni tipi Vmesniki Enostavni tipi

Samoopisujoi tipi

Kazalni tipi

Razredi Uporab. def. strukturni tipi Natevni tipi Navadni razredi

Polja

Vrednostni tipi v katli

Delegati

Slika 2.1: Pregled in organizacija podatkovnih tipov. Pri sklicnih tipih se lahko zgodi, da se dve spremenljivki sklicujeta na iste podatke. V tem primeru lahko operacije nad eno spremenljivko vplivajo na vrednosti podatkov, na katere se sklicuje druga spremenljivka. Pri vrednostnih tipih hrani vsaka spremenljivka svojo kopijo podatkov, zato ni mogoe, da bi operacije nad

16

OSNOVE C#

eno spremenljivko vplivale na podatke, ki jih hrani druga spremenljivka. Oglejmo si definiciji spremenljivk vrednostnega in sklicnega tipa: int i = 123; // vrednostni tip int // sklicni tip string

string s = "Pozdravljen svet";

Razliko v nainu hranjenja podatkov med obema spremenljivkama prikazuje slika 2.1: i s 123 "Pozdravljen svet"

Slika 2.2: Vrednostni in sklicni podatkovni tip. Iz razlike pri hranjenju vrednosti, izvirajo tudi ostale razlike med vrednostnimi in sklicnimi tipi: Pri vrednostnih tipih je vrednost shranjena na skladu ali pa je neposredno vrinjena v drug (sestavljen) tip. Pri sklicnih tipih je vrednost shranjena na kopici. Pri vrednostnih tipih predstavlja operacija prirejanja kopiranje vrednosti. Pri sklicnih tipih predstavlja operacija prirejanja kopiranje sklica, ne pa tudi vrednosti. Definicija spremenljivke vrednostnega tipa vkljuuje tudi inicializacijo pripadajoe vrednosti. Definicija spremenljivke sklicnega tipa vkljuuje inicializacijo sklica, ne pa tudi pripadajoe sklicane vrednosti, ki se ji ree izvod. Izvod je potrebno ustvariti posebej z uporabo operatorja new.

Tako kot Java, nudi tudi C# podporo za avtomatsko upravljanje s pomnilnikom. Programerju zato ni potrebno skrbeti za sproanje pomnilnika, ki ga zasedajo odrabljene vrednosti sklicnih tipov (razen vrednosti kazalnih tipov). Poseben tip predstavlja tip void. Uporabljamo ga kot vraajoi tip metod, ki ne vraajo nobene vrednosti.

2.3.2 Vrednostni tipi


Osnovna znailnost vrednostnih tipov je, da so njihove vrednosti shranjene neposredno in ne preko sklica, kot to velja za sklicne tipe. Pri tem mora shranjena vrednost vedno ustrezati tipu spremenljivke in ta ne more vsebovati vrednosti null. Vrednostne tipe razdelimo na naslednje skupine: strukturni tipi (angl. struct types) o enostavni tipi (angl. build-in simple types) celotevilni tipi realni tipi decimalni tip logini tip

17

OSNOVE C#

uporabniko doloeni strukturni tipi (angl. user-defined struct types)

natevni tipi (angl. enumeration types)

Strukturni tipi temeljijo na jezikovnem elementu struct, natevni pa na jezikovnem elementu enum. Podrobneja razlaga in opis uporabe strukturnih tipov se nahaja v poglavju :todo: 2.3.2.1 Enostavni tipi Ti tipi so vgrajeni v C# in predstavljajo najosnovneje podatkovne tipe. Te lahko uporabljamo neposredno ali pa jih uporabimo pri izgradnji zapletenejih sestavljenih tipov. Vgrajene strukturne tipe sestavljajo skupina celotevilnih tipov, skupina realnih tipov, decimalni tip in logini tip. Izbira ustreznega tipa je odvisna od vrste podatka, pri celotevilnih in realnih tipih pa tudi od zahtevanega razpona shranjene vrednosti. Vsi enostavni tipi so pravzaprav druga imena za sistemske tipe Ogrodja .NET. Tip int je na primer drugo ime za strukturo System.Int32. Spremenljivke enostavnega tipa lahko inicializiramo z uporabo konstantnih vrednosti. Celotevilne tipe prikazuje naslednja tabela: TIP sbyte RAZPON -128 do 127 0 do 255 U+0000 do U+ffff -32.768 do 32.767 0 do 65.535 -2.147.483.648 do 2.147.483.647 0 do 4.294.967.295 -9.223.372.036.854.775.808 do 9.223.372.036.854.775.807 0 do 18.446.744.073.709.551.615 FORMAT predznaeno 8 bitno celo tevilo 8 bitno celo tevilo 16 bitni znak unicode predznaeno 16 bitno celo tevilo 16 bitno celo tevilo predznaeno 32 bitno celo tevilo 32 bitno celo tevilo predznaeno 64 bitno celo tevilo 64 bitno celo tevilo

byte char short

ushort int

uint long

Ulong

Realne tipe prikazuje naslednja tabela: TIP float PRIBLIEN RAZPON 1.5 10-45 do NATANNOST 7 tevk FORMAT 32 bitno tevilo s

18

OSNOVE C#

3.4 1038 double 5.0 10-324 do 1.7 10308 15-16 tevk

plavajoo vejico 64 bitno tevilo s plavajoo vejico

Decimalni tip (tip decimal) je podoben realnim tipom saj prav tako hrani numerino vrednost v obliki s plavajoo vejico. V primerjavi z realnimi tipi pa dosega vejo natannost in manji razpon. Lastnosti decimalnega prikazuje naslednja tabela: TIP decimal PRIBLIEN RAZPON 1.0 10-28 do 7.9 1028 NATANNOST 28-29 tevk FORMAT 128 bitno tevilo s plavajoo vejico

Logini tip (tip boolean) je namenjen spremenljivkam, ki lahko hranijo le logini vrednosti resnica (true) in neresnica (false): TIP boolean RAZPON true, false

Primeri deklaracij enostavnih tipov so: int irina = 3, viina = 4; char prviZnak = 'a'; decimal minZnesek = -2000000.0m; 2.3.2.2 Uporabniko definirani strukturni tipi Uporabniko definirani strukturni tipi so vrednostni tipi, ki jih lahko definiramo sami. Uporabniko definirane strukturne tipe definiramo z definicijo nove strukture ob uporabi kljune besede struct. Strukture (tip struct) so podobne razredom (tip class). Oba tipa se med seboj razlikujeta v naslednjem: Strukture so vrednostni tip, razredi pa so sklicni tip. Ker so strukture vrednostni tip se ustvarijo na skladu in ne v kopici, pri prenaanju v metodo pa se prenesejo po vrednosti in ne po sklicu. Struktura ne more dedovati po drugi strukturi ali razredu, prav tako struktura ne more biti osnova za dedovanje razredov. Kljub temu strukture lahko, tako kakor razredi, izvedejo vmesnik. Inicializacije lastnosti strukture ni mogoe izvesti z inicializatorji. Strukture ne smejo vsebovati eksplicitnega konstruktorja brez parametrov. // ni ni narobe e uporabljamo umnike

Strukture so e posebej primerne za predstavitev majhnih sestavljenih podatkovnih tipov, pri katerih ne potrebujemo dedovanja in sklicnih lastnosti ali ko potrebujemo vrednostno prirejanje. Primera takih sestavljenih podatkovnih tipov sta predstavitev kompleksnih tevil ali tok v koordinatnem sistemu. S preoblaganjem in prekrivanjem operatorjev lahko doseemo, da se sestavljeni strukturni tipi vedejo enako kot vgrajeni enostavni tipi. Strukturo deklariramo na naslednji nain:

19

OSNOVE C#

[atributi] [pridevniki] struct ime [:vmesniki] {telo} [;] Tako deklarirano strukturo lahko nato uporabljamo pri deklaraciji spremenljivk kot bi uporabljali vgrajeni tip. Primer enostavne deklaracije strukture je: public struct Toka { public int x,y; } Tako strukturo lahko nato uporabimo pri deklaraciji spremenljivke, kot v naslednjem primeru: Toka t1; Toka t2 = new Toka(); // inicializator je kar new

Comment [h1]: Obrazloi kaj je to.

Podrobneji opis deklaracije strukture je zaradi podobnosti z razredom na tem mestu izpuen. Ob upotevanju opisanih razlik med strukturo in razredom, lahko podrobnejo razlago deklaracije najdete v razdelku posveenemu razredom. 2.3.2.3 Natevni tipi Natevni tip omejuje vrednosti, ki jih lahko zasede podatek na seznam imenovanih vrednosti. Poglejmo si primer natevnega tipa za mesece: enum Meseci {Jan,Feb,Mar,Apr,Maj,Jun,Jul,Avg,Sep,Okt,Nov,Dec}; Imenovane vrednosti so v osnovi predstavljene z numerino vrednostjo v osnovnem tipu, ki je lahko katerikoli enostaven celotevilni tip razen tipa char. Privzeti osnovni tip je int. Prva imenovana vrednosti s seznama ima numerino vrednost 0, vsaka naslednja pa je za 1 veja od predhodne. Osnovne numerine vrednosti lahko tudi spremenimo: enum Ocene {Negativno = 5, Zadostno, Dobro, PravDobro = 9, Odlino}; Natevni tip v splonem deklariramo na naslednji nain: [atributi] [pridevniki] enum ime [:osnovni_tip] {seznam_imenovanih_vrednosti};

2.3.3 Sklicni tipi


V programski kodi C# lahko uporabljamo pet vrst sklicnih tipov: polje (angl. array), razred (angl. class), vmesnik (angl. interface), delegat (angl. delegate) in kazalni tip (angl. pointer).

20

OSNOVE C#

Vrednosti, ki pripadajo sklicnemu tipu, so sklici na izvode tipov. Izvodom reemo tudi predmeti. Pri definiciji spremenljivke sklicnega podatkovnega tipa se sklic inicializira na vrednost null, ki predstavlja nevzpostavljen sklic. Izvod je potrebno ustvariti posebej z uporabo operatorja new. Pri prirejanju spremenljivki sklicnega tipa se naredi le kopija sklica, ne pa tudi kopija sklicane vrednosti. 2.3.3.1 Polja Polje je podatkovna struktura, ki vsebuje mnoico spremenljivk, do katerih dostopamo preko indeksov. Vsebovane spremenljivke, ki jim pravimo elementi polja, morajo biti istega tipa. Tip elementov polja je lahko poljuben tip, vkljuno z poljem. Polje je lahko eno-dimenzionalno ali ve-dimenzionalno. Vsaka od dimenzij polja ima svojo dolina, ki je celo tevilo veje ali enako 0. Doline dimenzij polja niso del definicije polja, temve se vspostavijo v asu izvajanja, ko se ustvari izvod polja. Enodimenzionalno in vedimenzionalno polje definiramo na naslednji nain: T[] spremenljivka T[,, ... ,] spremenljivka Pri tem je T poljubni tip, ki predstavlja tip elementov polja. Dimenzija polja je enaka tevilu znakov "," znotraj oglatih oklepajev poveanemu za ena. V naslednjem primeru definiramo en-dimenzionalno in tri-dimenzionalno polje elementov: int[] ocene; // dolina polja ni del definicije tipa

double[,,] pritisk1; // 3 dimenenzionalno polje realnih tevil Tip elementov polja je lahko spet polje. e elimo definirati polje pri katerem je vsak element polja spet neko polje, je potrebno v definiciji tipa navesti zaporedje oglatih oklepajev, ki predstavljajo posamezna polja in njihove dimenzije. Pri tem se hierarhija polj in njihovih dimenzij od krovnega do najbolj elementarnega doloi iz seznama z branjem od leve proti desni. e na primer elimo definirati enodimenzionalno polje dvodimenzionalnih polj celih tevil, lahko to storimo na naslednji nain: double[][,] pritisk2; V zgornjih primerih definicij polja smo definirali podatkovne tipe in spremenljivke, nismo pa e ustvarili izvodov definiranih podatkovnih tipov. To storimo z operatorjem new, kar prikazujeta naslednja primera: int[] ocene; ocene = new int[108]; // v dveh // vrsticah // v eni vrstici

double[,,] pritisk1 = new double[10,100,100];

Kadar uporabljamo polje polj moramo inicializacijo izvoda narediti v ve korakih. V prvem koraku ustvarimo in inicializiramo krovno polje. ele v drugem koraku lahko ustvarimo in inicializiramo elemente prvega polja, ki so spet polja. double[][,] pritisk2;

21

OSNOVE C#

// meritve = new double[10][100,100]; meritve = new double[10][,];

napaka !!!

// pravilno !!!

for (int i = 0; i < 10; i++) meritve[i] = new double[100,100]; Ker se vsako elementarno polje (pod-polje) ustvari posebej, lahko to iskoristimo za ustvarjanje nepravokotnih ve-dimenzionalnih polj. V naslednjem primeru ustvarimo trikotno dvo-dimenzionalno polje celih tevil: int[][] trikotnik = new int[10][]; for (int i = 0; i < 10; i++) trikotnik[i] = new int[i]; 2.3.3.2 Razredi Razred je osnovni programski gradnik in predstavlja temelj za nartovanje in izgradnjo programov v programskem jeziku C#. Formalno je razred podatkovna struktura, ki lahko vkljuuje podatkovne lane (spremenljivke, konstante in polja), funkcijske lane (metode, lastnosti, dogodke, indekserje, operatorje, konstruktorje in destruktorje) in vgnezdene tipe. V programu predstavljajo razredi podatkovni tip za izdelavo predmetov. Razredi podpirajo dedovanje. Podobno, kot pri jeziku Java, je dovoljeno le enkratno dedovanje. Vekratno dedovanje lahko nadomestimo z vekratnim dedovanjem vmesnikov. Med razredi imata posebno mesto vgrajena tipa object in string, ki sta sklicna razredna tipa. Tip object je osnovni razred za vse ostale tipe. Vsak tip v C# neposredno ali posredno izhaja iz razreda object. Kljuna beseda object je drugo ime za vnaprej definiran razred System.Object. Tip string slui za predstavitev niza znakov Unicode. Kljuna beseda string je drugo ime za vnaprej definiran razred System.String. Razred v splonem deklariramo na naslednji nain: [atributi] [pridevniki] class ime [:seznam_prednikov] { telo }[;] Deklaracijo razreda smo lahko zasledili v naem prvem programu C#: class MojPrviRazred { static void Main(string[] args) { Console.WriteLine("Pozdravljen svet!"); } } Podatkovni tip razred je podrobneje opisan v poglavju :todo:. 2.3.3.3 Vmesniki Vmesnik je podatkovna struktura, ki slui opisu uporabe razredov ali struktur. V ta namen za razliko od razreda ne vkljuuje podatkovnih lanov in vgnezdenih tipov, temve le nekatere funkcijske lane (metode, lastnosti, dogodke ali indekserje) in

22

OSNOVE C#

to brez njihove izvedbe oziroma telesa. Vmesnik torej slui doloitvi lanov, ki jih mora vsebovati razred (ali struktura), ki je naslednik vmesnika, ne pa njihove izvedbe. Vmesnik v splonem deklariramo na naslednji nain: [atributi] [pridevniki] interface ime [:seznam_prednikov] { telo }[;] Sledi primer enostavne definicije vmesnika. Iz tega vmesnika izpeljani razredi ali strukture, morajo vsebovati metodo, ki jo doloa vmesnik. interface IIzpisljivo { void Izpii(); // ni telesa metode } class Toka : IIzpisljivo { int x,y; public void Izpii() { Console.WriteLine("(", x, ",", y, ")"); } } 2.3.3.4 Delegati Delegat je poseben razred, ki ga lahko uporabimo za posredovanje metod. Izvod delegata predstavlja metodo, ki jo lahko tako prenaamo kot parameter pri klicu drugih metod. Delegati omogoajo varno izvajanje funkcionalnosti, ki jo navadno doseemo s kazalci na funkcije. Delegata v splonem deklariramo na naslednji nain: [atributi] [pridevniki] delegate vrnjeni_tip ime ([parametri]); Oglejmo si primer deklaracije, izdelave in uporabe delegata: delegate double Del(double x); static void DemoDelegates() { Del delInst = new Del(Math.Sin); // izdelava izvoda double x = delInst(1.0); } 2.3.3.5 Kazalni tipi Kazalni podatkovni tipi se od ostalih sklicnih tipov razlikujejo po obravnavi predmetov na katere kaejo, saj ti niso pod nadzorom sistema za avtomatsko upravljanje z pomnilnikom (smetarja). Kazalne tipe lahko uporabljamo le tistih delih programske kode, ki smo jo z kljuno besedo unsafe oznaili za nevarno. // uporaba delegata // deklaracija

23

OSNOVE C#

"Klasini" kazalni tipi so v C# le redko potrebni. Tudi tradicionalni podroji uporabe, nizi, prenos parametrov po sklicu in prenos funkcij, so v jeziku C# reeni na varen nain, brez uporabe kazalcev. Kljub temu pa pridejo vasih prav; na primer pri prenosu programske kode pisane za C ali C++ v programski jezik C#. Prav tako pa so kazalni tipi zelo uporabni pri uporabi zunanjih knjinic, ki uporabljajo kazalce. Kazalni tip definiramo na naslednji nain: tip* prim tem predstavlja tip osnovni tip na katerega lahko kae kazalni podatkovni tip. Definicija kazalnega tipa je navadno vkljuena v deklaracijo spremenljivke kazalnega tipa, kot na primer v naslednji deklaraciji: int* ptevilo; // deklarirali smo kazalec na tip int

Kazalni tip torej doloimo z znakom *, ki sledi tipu, ki je osnova za kazalni tip. Pri delu z kazalnimi tipi lahko uporabljamo operatorje za delo z kazalci (*, ->, & ...), ki jih poznamo iz programskih jezikov C in C++. Naslednji primer nam prikazuje deklaracijo kazalca na znak in pripadajoe kazalne spremenljivke. Za delo s kazalci imamo na razpolago operatorje class Test { static void Main() { int i; unsafe { int* p = &i; *p = 123; } Console.WriteLine(i); } }

2.4 Spremenljivke in parametri


2.4.1 Spremenljivke
Spremeljivke so programski elementi, ki so namenjeni pomnjenju in dostopu do podatkovnih vrednosti. Vrednost, ki jo hrani neka spremenljivka, se lahko med tekom programa spreminja (spomnimo se, da so konstantne vrednosti programski elementi, ki hranijo nespremenljive vrednosti). Spremenljivke so torej spominska mesta. Vsaka spremenljivka pripada nekemu definiranemu podatkovnemu tipu, ki doloa kakne vrste vrednosti lahko spremenljivka pomni. V C# torej lahko spremenljivke hranijo le vrednosti, ki pripadajo istemu podatkovnemu tipu.

24

OSNOVE C#

2.4.1.1 Deklaracija spremenljivk V okviru deklaracije spremenljivki doloimo ime in tip, poleg tega pa ji lahko doloimo tudi zaetno vrednost: [pridevniki] tip ime [inicializator]; V istem stavku lahko deklariramo tudi ve spremenljivk istega tipa: [pridevniki] tip ime [inicializator] [,ime [inicializator] [...]]; Primeri veljavnih deklaracij so: int a; double irina = 3, viina = 4; 2.4.1.2 Lokalne in lanske spremenljivke Lokalne spremenljivke so deklarirane v telesih metod, lastnosti ali indekserjev. Deklaracija lokalni spremenljivki ne dodeli zaetne vrednosti, zato jo je potrebno pred uporabo inicializirati. Oglejmo si primer: static void Main(string[] args) { int a; a = 2; } lanske spremenljivke so deklarirane kot lanice razredov ali struktur. lanske spremenljivke, ki so deklarirane s pridevnikom static pripadajo razredom oziroma strukturam, tiste ki pa so deklarirane brez pridevnika static, pripadajo njihovim izvodom. Deklaracija lanski spremenljivki dodeli privzeto zaetno vrednost, zato lanskih spremenljivk ni potrebno eksplicitno inicializirati: struct Toka { public int x,y; } class Test { static void Main(string[] args) { Toka t = new Toka(); System.Console.WriteLine("(" + t.x + "," + t.y + ")"); System.Console.ReadLine(); } } // lanske spremenljivke niso inicializirane // inicializacija pred prvo uporabo je obvezna !!! System.Console.WriteLine(a);

25

OSNOVE C#

Privzete vrednosti pri inicializaciji spremenljivk so naslednje: TIP bool char enum numerini tipi struct PRIVZETA VREDNOST false '\0' E(0), kjer je E ime natevnega tipa 0 vrednost, ki ima vse lanske spremenljivke vrednostnega tipa nastavljene na privzete vrednosti in vse lanske spremenljivke sklicnega tipa nastavljene na vrednost null null

sklicni tipi

2.4.1.3 Nespremenljive spremenljivke konstante Z kljuno besedo const lahko spremenimo deklaracijo lanske ali kostantne spremenljivke na tako, da spremenljivke ni mo spreminjati: const float pi = 3.14f; const int r = 123 * 7; Besedo const lahko uporabimo pri deklaraciji spremenljivk naslednjih tipov: byte, char, short, int, long, float, double, decimal, bool, string, natevni tip in sklicni tip. Konstantno spremenljivko moramo pri deklaraciji tudi inicializirati, inicializacijski izraz pa mora biti izraunljiv v asu prevajanja. Zaradi tega so dovoljene vrednosti za sklicne tipe konstantni niz ali vrednost null;

2.4.2 Parametri
Parametri so spremenljivke, ki omogoajo prenos vrednosti v metode, nekateri pa tudi prenos vrednosti iz metod. Parametri ob klicu metod so lahko: obiajni (vrednsotni) parametri sklicni parametri izhodni parametri polje parametrov

2.4.2.1 Obiajni parametri Obiajni parametri omogoajo "prenos parametra po vrednosti" in jim lahko reemo tudi vrednostni ali vhodni parametri. Taki parametri se prenesejo v metodo z operacijo prirejanja novi kopiji parametra. To pomeni, da imamo v primeru vrednostnega tipa znotraj metode na voljo kopijo vrednosti, v primeru sklicnega tipa pa kopijo sklica. Kopija parametra je izven metode nedostopna in obstaja le do konca izvajanja metode. Spreminjanje obiajnega parametra v metodi torej ne

26

OSNOVE C#

vpliva na originalen argument. Uporabo obiajnih parametrov nam demonstrira naslednji primer: class Test { static void Zamenjaj1(int v1, int v2) // vrednostni param. { int temp = v1; v1 = v2; v2 = temp; } static void Main() { int arg1 = 1, arg2 = 2; Zamenjaj1(arg1, arg2); } } 2.4.2.2 Sklicni parametri Sklicni parametri omogoajo "prenos parametra po sklicu". Sklicni parametri omogoajo, da se v metodo prenese sklic na originalen argumenta, zato je spreminjanje parametra v metodi vidno tudi izven same metode. Ob klicu metode mora biti sklicni parameter inicializiran. Sklicni parameter mora biti deklariran s pridevnikom ref. Pridevnik ref mora biti uporabljen tudi pri samem klicu metode s sklicnim parametrom: class Test { static void Zamenjaj2(ref int v1, ref int v2) { int temp = v1; v1 = v2; v2 = temp; } static void Main() { int arg1 = 1, arg2 = 2; Zamenjaj2(ref arg1, ref arg2); } } // nujna je inicializacija // zamenjava bo uspena! // sklicna param. // zamenjava ne bo uspena System.Console.WriteLine(arg1 + " " + arg2);

System.Console.WriteLine(arg1 + " " + arg2);

27

OSNOVE C#

2.4.2.3 Izhodni parametri Izhodni parametri so podobni sklicnim. Razlikujejo se po tem, da je njihova zaetna vrednost ob klicu metode nepomembna, zato za njih ne velja, da mora biti njihova vrednost ob klicu metode inicializirana. Ne glede na vrednost parametrov pred klicem metode velja, da je na zaetku izvajanja metode vrednost izhodnih parametrov neinicializirana. Izhodne parametre je torej nujno potrebno znotraj metode inicializirati. Z izhodnimi parametri lahko prenaamo vrednosti le ven iz metode. Izhodni parameter mora biti deklariran s pridevnikom out. Pridevnik out mora biti uporabljen tudi pri samem klicu metode z izhodnim parametrom. class Test { static void Init(out int v1, out int v2) { // v2 = v1; v1 = 108; v2 = 27; } static void Main() { int arg1 = 10, arg2; Init(out arg1, out arg2); } } 2.4.2.4 Polje parametrov Mehanizem polja parametrov omogoa klic metod s spremenljivo dolino seznama argumentov (angl. variable length argument list). Polje argumentov deklariramo s pridevnikom params: class Test { static int Setej(params int[] tevila) { int vsota = 0; for (int i = 0; i < tevila.Length; i++) vsota = vsota + tevila[i]; return vsota; } static void Main() { // inicializacija ni nujna // zamenjava bo uspena! // napaka - v1 ni inicializiran

28

OSNOVE C#

int arg1 = 1, arg2 = 3; int Setevek = Setej(arg1, 2, arg2, 4, 5, 6, 7); System.Console.WriteLine(Setevek); } }

2.5 Izrazi in operatorji


Izraz je zaporedje operatorjev in operandov, ki doloajo izraun vrednosti ali doloajo spremenljivko ali konstanto. V izrazih, kjer nastopa ve operatorjev, se ti izvedejo v vrstnem redu, kot to doloa njihova prioriteta. Operator z najvijo prioriteto se bo izvedel prvi, rezultat te operacije pa bo nastopal kot operand v naslednjem koraku izrauna celotnega izraza. Izraz: a = b + c * d; se bo tako izvedel kot a = b + (c * d); saj ima operator mnoenja vijo prioriteto kot operator setevanja. V izrazu, kjer nastopa ve operatorjev z enako prioriteto, doloa vrstni red izvajanja njihova asociativnost (nain povezave). Operatorji se lahko povezujejo z leve proti desni ali z desne proti levi. Pri tem velja, da se vsi binarni operatorji, razen operatorjev prirejanja, povezujejo z leve proti desni. Operatorji prirejanja in pogojni operator (?:) se povezujejo z desne proti levi. Torej se bosta izraza: x - y - z; a = b = c; izvedela kot: (x - y) - z; a = (b = c); Prioriteto in povezovanje operatorjev lahko kontroliramo z uporabo oklepajev. Prikazanemu zaporedju odtevanj: x y z lahko spremenimo nain izvajanja z naslednjo postavitvijo oklepajev: x (y z); Naslednja tabela vsebuje operatorje urejene po njihovi prioriteti od najvije do najnije:

29

OSNOVE C#

Vrsta Primarni Unarni multiplikativni Aditivni Pomik relacijski in pretvorba tipov Enakost logini AND logini XOR logini OR pogojni AND pogojni OR Pogojni Prireditev

operatorji x.y f(x) a[x] x++ x-new typeof checked unchecked + * + << < == & ^ | && || ?: = *= /= %= += -= <<= >>= &= ^= |= > != / >> <= >= is as ! % ~ ++x --x (T)x

2.6 Programski stavki


Programski stavki (angl. statements) so zakljuena programska navodila. Izvajanje programskega stavka razen redkih izjem (prazen stavek ali blok in podobno) povzroi spremembo stanja izvajanja programa. Programski stavki se izvajajo zaporedoma. Programski stavek je lahko na primer prireditveni izraz, klic metode, deklaracija spremenljivke ali konstante, pogojni stavek in drugo. Med programske stavke sodi tudi stavni blok, ki ga sestavlja seznam ni ali ve programskih stavkov vsebovanih znotraj zavitih oklepajev. En programski stavek se lahko razteza prek ve vrstic. Po drugi strani pa je lahko v eni vrstici ve stavkov. Oglejmo si nekaj primerov programskih stavkov: povrina = irina * dolina; ClearScreen(); int index; { int i=GetResult(); Console.Write(i); }

30

OSNOVE C#

Programske stavke lahko razdelimo na naslednje skupine: stavni blok ({}) prazen stavek (;) stavek z oznako stavek z deklaracijo stavek z izrazom stavka z vejanjem (if in switch) zanke (while, do, for in foreach) stavki s skoki (break, continue, goto, return in throw) stavek za lovljenje izjem (try) stavek za preverjanje ali nepreverjanje prekoraitve (checked, unchecked) stavek za zaklepanje (lock) stavek za uporabo vira (using)

Uporaba stavkov je na kratko prikazana v naslednjih razdelkih. Nekateri stavki so podrobneje razloeni v drugih poglavjih. 2.6.1.1 Stavni blok Stavni blok (angl. block) omogoa uporabo ve stavkov na mestu, kjer je dovoljen en sam programski stavek. Stavni blok je seznam programskih stavkov znotraj zavitih oklepajev. using System; class Test { static void Main() { // if priakuje en stavek ali stavni blok if (DateTime.Today.DayOfWeek == DayOfWeek.Sunday) Console.WriteLine("V nedeljo se ne dela"); if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday) { Console.WriteLine("V soboto se ne dela"); Console.WriteLine("V soboto se zabava"); } } }

31

OSNOVE C#

2.6.1.2 Prazen stavek Prazen stavek (angl. empty statement) je stavek, ki ne stori niesar. Uporabimo ga na mestih kjer ni potrebno niesar storiti, kjub temu pa je zaradi sintakse jezika potrebno zapisati programski stavek. Prazen programski stavek predstavlja znak podpije (;). class Test { static void Main() { while (System.Console.ReadLine().Length == 0) ; } } 2.6.1.3 Stavek z oznako Stavek z oznako omogoa oznaevanje posameznih stavkov in ga uporabljamo v kombinaciji s stavkom goto. Programski stavek oznaimo tako, da pred njega postavimo oznako, ki mu sledi znak za dvopije (:). Oznaka je predstavljena z imenom v skladu z opisom v poglavju 2.2.1. Stavek z oznako se lahko nahaja znotraj drugih stavkov le v okviru stavnega bloka. Doseg oznake je celoten stavni blok v katerem je ta deklarirana, vkljuno z vgnezdenimi bloki. int Abs(int tevilo) { if (tevilo >= 0) goto narejeno; tevilo = -1 * tevilo; narejeno: return tevilo; } 2.6.1.4 Stavek z deklaracijo Stavek z deklaracijo (angl. declaration statement) izvede deklaracijo ene ali ve lokalnih spremenljivk ali lokalnih konstant. V sklopu deklaracije lahko deklariramo ve spremenljivk istega podatkovnega tipa. Tako kot stavek z oznako, se lahko stavek z deklaracijo nahaja znotraj drugih stavkov le v okviru stavnega bloka. class Test { static void Main() { int x = 108, y = 27; double tea; tea = 7.3; System.Console.WriteLine(x + " " + y + " " + tea); // deklaracija z inicializacijo // deklaracija // stavek z oznako // PRAZEN STAVEK

32

OSNOVE C#

} } 2.6.1.5 Stavek z izrazom Stavek z izrazom (angl. expresion statement) je stavek, ki vsebujejo nek izraz, kot je na primer prirejanje, klic funkcije ali podobno. Velja pa, da niso vsi izrazi tudi legalni programski stavki. Primer veljavnega programskega stavka z izrazom je: x = a + 2; // veljaven programski stavek Primer nedovoljenega programskega stavka je: x + y; // NAPAKA - nedovoljen programski stavek

2.6.1.6 Stavka z vejanjem (if in switch) Stavka za vejanje (angl. selection statements) na podlagi vrednosti nekega izraza preusmerijo zaporedje izvajanja programa na enega od monih programskih stavkov. C# pozna dva stavka za vejanje: stavek if in stavek switch. Stavek if izbere stavek, ki se bo naslednji izvajal, na podlagi vrednosti loginega izraza. class Test { static void Main(string[] args) { if (args.Length == 0) else { System.Console.WriteLine("Argumenti so."); System.Console.WriteLine("Prvi argument je " + args[0]); } } } Stavek switch izbere seznam stavkov, ki se bodo naslednji izvajali, na podlagi ujemanja med vrednostjo preklopnega izraza (angl. switch expression) in preklopnimi oznakami (angl. switch labels). Preklopni izraz se nahaja znotraj okroglih oklepajev takoj za kljuno besedo switch, ki je prvi osnovni element stavka switch. Tip preklopnega izraza je lahko celostevilen (sbyte, byte, short, ushort, int, uint, long, ulong, char), kar poznamo e iz jezikov C, C++ in Java, ali pa ustreza podatkovnemu tipu string, kar je novost. Drugi del stavka switch predstavlja zaporedje razdelkov, ki so sestavljeni iz ene ali ve preklopnih oznak in seznama pripadajoih stavkov. Stavek switch bo izvedel tiste stavke, ki pripadajo preklopni oznaki, ki je enaka vrednosti preklopnega izraza. Med preklopnimi oznakami ima posebno vlogo oznaka default, ki predstavlja vse vrednosti, ki ne ustrezajo nobeni drugi preklopni // if ovrednosti logini izraz System.Console.WriteLine("Ni argumentov.");

33

OSNOVE C#

oznaki. V primeru, ko ne uporabimo oznake default in izrazu ne ustreza nobena oznaka, se izvajanje stavka switch kona. static void Main(string[] args) { switch (args.Length) { case 0: Console.WriteLine("Brez argumentov"); break; case 1: Console.WriteLine("En argument"); break; default: int n = args.Length; Console.WriteLine("{0} argumentov", n); break; } } 2.6.1.7 Zanke (while, do, for in foreach) Programski jezik C# pozna tiri vrste stavkov za zanke (angl. iteration statements). Tri izmed njih poznamo e iz jezikov C, C++ in Java, stavek foreach pa predstavlja novost. Stavek while izvaja vgnezdeni stavek ali stavni blok vse dokler je pripadajoi logini izraz resnien. Pri stavku while se preveri resninost loginega izraza pred izvajanjem zanke, zato se lahko stavek while kona ne da bi se zanka sploh izvedla. class WhileTest { static void Main(string[] args) { int i = 0; while (i < args.Length) { System.Console.WriteLine(args[i]); i++; } } }

34

OSNOVE C#

Stavek do je podoben e opisanemu stavku while in izvaja vgnezdeni stavek ali stavni blok vse dokler je pripadajoi logini izraz resnien. Od stavka while se razlikuje po temu, da se resninost loginega izraza preveri vsakokrat po izvajanju zanke, zato se zanka gotovo izvede vsaj enkrat. using System.Collections; class DoTest { static void Main(string[] args) { string vrstica; ArrayList seznam = new ArrayList(); do { vrstica = System.Console.ReadLine(); seznam.Add(vrstica); } while (!vrstica.Equals("exit")); } } Stavek for je e tretja variacija s katero lahko doloimo zanko. Ker poleg loginega izraza vkljuuje tudi izraz za inicializacijo zanke in iteracijski izraz, ki se izvede na koncu vsakega izvajanja zanke, omogoa pisanje strnjenih zank. Stavek for izvaja vgnezdeni stavek ali stavni blok vse dokler je pripadajoi logini izraz resnien. Pred prvim izvajanjem zanke se izvede inicializacijski izraz, po vsakem izvajanju zanke pa se izvede iteracijski izraz in se preveri resninost loginega izraza. Stavek for je torej nekoliko drugae zapisana zanka do. class ForTest { static void Main(string[] args) { for (int i = 0; i < args.length; i++) System.Console.WriteLine(args[i]); } } Nekoliko drugaen od predhodno opisanih stavkov za zanke je stavek foreach, saj ne vsebuje izhodnega pogoja, ki ga v drugih zankah predstavlja logini pogoj. Stavek foreach izvede vgnezdeni stavek ali stavni blok za vsak element podanega polja ali podane zbirke (angl. collection) predmetov. Ker je velikost polja ali zbirke znana, nam pri uporabi stavka foreach ni potrebno skrbeti za inicializacijo zanke, izhodni pogoj in iteracijski izraz. Vsakokratni element polja ali zbirke nam je znotraj zanke na voljo preko spremenljivke, ki predstavlja sklic na ta element. Stavek foreach uporabljamo predvsem za pridobivanje potrebnih podatkov iz polj in zbirk.

35

OSNOVE C#

Pri spreminjanju vsebine polj in zbirk pa moramo biti pazljivi, saj nam zanka foreach ne omogoa neposrednega dostopa do sklicov na vsebovane elemente, temve le do njihovih kopij. class ForeachTest { static void Main(string[] args) { foreach (string s in args) Console.WriteLine(s); } } 2.6.1.8 Stavki s skoki (break, continue, goto, return in throw) nadaljuj!!! 2.6.1.9 Goto, oznake, stavni blok in vejanje "if" static void Main(string[] args) { if (args.Length == 0) Console.WriteLine("Brez argumentov"); else {Console.WriteLine("Parametri so"); // STAVNI BLOK goto done; } Console.WriteLine("Skoraj konec"); done:; } 2.6.1.10 Iteracije for in foreach // OZNAKI MORA SLEDITI STAVEK (ETUDI PRAZEN) // ...

static void Main(string[] args) { for (int i = 0; i < args.length; i++) Console.WriteLine(args[i]); } Iteracijski stavek foreach je uporaben za polja in zbirke (collections). Stavka foreach ne smemo uporabljati, ko spreminjamo elemente polja ali zbirke. static void Main(string[] args) { foreach (string s in args) Console.WriteLine(s);

36

OSNOVE C#

} 2.6.1.11 break, continue in return

Programski stavek break kona zanko ali vejanje v katerem se nahaja, programski stavek continue pa prenese kontrolo na naslednjo iteracijo zanke v kateri se nahaja. Njun sorodnik je stavek return, ki kona izvajanje metode v kateri se nahaja. static void Main(string[] args) { int i = 0; while (true) { Console.WriteLine(args[i++]); if (i < args.Length) continue; break; } return i; } 2.6.1.12 Bolj nenavadni stavki

Programski stavek lock je podoben Javanskemu synchronized. Stavek lock uporabljamo pri zaklepanju doloenih delov programske kode pri programiranju ve-nitnih aplikacij. Stavka checked in unchecked uporabljamo za doloanje preverjanja aritmetinega prekoraenja. Stavek using uporabljamo, ko elimo znotraj enega stavka zajeti nek vir (ustvariti predmet), izvesti potrebno procesiranje in vir (predmet) takoj sprostiti. using (Font myFont = new Font("Arial")) { // uporabljaj myFont }

37

OSNOVE C#

2.7 Imenski prostori


Imenski prostor (namespace) je jezikovni element, ki nam pomaga pri organizaciji programske kode in zmanjuje morebitne konflikte pri imenovanju in uporabi imen v programih. Imenski prostori so uporabno orodje pri notranji organizaciji programa, kakor tudi pri zunanji organizaciji, to je pri nainu kako je programski vmesnik izpostavljen drugim programom. Imenski prostor je podroje znotraj programa, ki omejuje neposreden doseg imen (deluje kot mapa imen). Poglejmo si primer: namespace Guru { class Toka { int x, y; } class rta { Toka t1,t2; } } // ime Toka uporabimo na ustaljen nain

class GlavniRazred { Toka[] toke; Guru.Toka[] toke; } V gornjem primeru smo razred z imenom Toka definirali znotraj imenskega prostora Guru. Znotraj tega imenskega prostora lahko uporabljamo ime Toka na ustaljen nain. Zunaj imenskega prostora Guru pa lahko dosegamo razred Toka le s predpono Guru, ki doloa imenski prostor v katerem je ime definirano: Guru.Toka. Kot je razvidno iz gornjega primera, doloamo imenske prostore s kljuno besedo namespace. Popolnoma veljavno je, da v programu ne doloimo nobenega imenskega prostora. V tem primeru imena, ki jih definiramo v takem programu, pripadajo globalnemu imenskemu prostoru. Imenski postori niso vezani na eno samo izvorno datoteko. Isti imenski prostor se lahko razteza preko ve izvornih datotek. Po drugi strani pa velja tudi obratno; ena izvorna datoteka lahko vsebuje ve imenskih prostorov: // ni v redu // ime Toka je znotraj imen. prost. Guru

38

OSNOVE C#

namespace Guru1 { // lani imenskega prostora Guru1 } namespace Guru2 { // lani imenskega prostora Guru2 } Imenske prostore lahko tudi gnezdimo, kar nam omogoa hierarhino organizacijo programske kode: namespace Guru { // lani imenskega prostora Guru namespace Teaji { // lani imenskega prostora Guru.Teaji } }

2.7.1 Uporaba imenskih prostorov


Opisani mehanizem imenskih prostorov omogoajo uporabo istega imena pri imenovanju razlinih gradnikov programa, e ti pripadajo razlinim imenskim prostorom. Na tak nain se lahko izognemo zmenjavi, ki nastane pri nenamernem vekratnem imenovanju. Do imen v imenskih prostorih lahko pridemo z uporabo v celoti kvalificiranega imena, ki je sestavljen z zaporedjem vseh potrebnih imenskih prostorov in samega imena, loenih s piko: na primer N1.N2.N3.A. e se na ime sklicujemo iz mesta v programu, ki je vkljuen v katerega izmed imenskih prostorov v zaporedju, ki doloa v celoti kvalificirano ime, potem lahko pridemo do elenega imena globlje v hierarhiji le z navedbo tistih imenskih prostorov, ki nas loujejo do imena: na primer N3.A. e pa je ime nije v hierarhiji imenskih prostorov, potem ga lahko doseemo le z uporabo osnovnega imena: na primer A. Tretji nain dostopa do imen v imenskih prostorih pa je uporaba direktive using. Ta omogoa dostop do imen v drugih imenskih prostorih le z navedbo osnovnega imena, zaporedje imenskih prostorov za dosego imena pa navedemo na enem mestu z direktivo using. Poglejmo si e znan primer:

39

OSNOVE C#

using System; class Test {

// enkrat navedemo potrebne imenske prostore

static void Main() { Console.Write('a'); Conslole.Write('b'); } } // upoteva se direktiva using // upoteva se direktiva using

2.8 Prevedi in izvedi


Za razvoj programske opreme na podlagi programskega jezika C# in platforme .NET ne potrebujemo razvojnega okolja Visual Studio .NET, temve nam zadoa nameen .NET Framework, preprost urejevalnik besedil in ukazno okno (command prompt). V okviru tega razdelka je opisan postopek prevajanja in izvajanja programov v C#-u iz ukazne vrstice.

2.8.1 Prevajanje enostavnega programa


Izvorno kodo programa v jeziku C# shranimo v eno ali ve datotek s konnico .cs. Izvorno kodo programa moramo pred izvajanjem najprej prevesti. V ukazni vrstici lahko to storimo z uporabo prevajalnika za jezik C#: csc MojProgram.cs ki ustvari izvajalno datoteko s konnico .exe, v naem primeru torej MojProgram.exe. Tudi v primeru, ko program sestavlja ve izvornih datotek, zaenemo prevajalnik samo enkrat. Prevajalnik pa zaenemo z ve argumenti izvornimi datotekami, ki sestavljajo na program: csc PrviDel.cs DrugiDel.cs Ve izvornih datotek, ki sestavljajo isti program lahko najlaje prevedemo, e jih shranimo v isti imenik. V tem primeru poenemo prevajalnik na preprost nain: csc *.cs V obeh primerih je rezultat prevajanja skupna izvajalna datoteka, ki pobere ime po tisti izvorni datoteki, ki vsebuje vhodno metodo Main. Pod predpostavko, da metodo Main vsebuje izvorna datoteka PrviDel.cs je rezultat prevajanja izvajalna datoteka PrviDel.exe.

40

OSNOVE C#

2.8.2 Doloanje izhodnega formata pri prevajanju


V predhodnih zgledih smo predpostavljali, da prevajamo izvajalni program in ne knjinico ter, da program za svoje delovanje ne bo potreboval tipov ali predmetov iz zunanjih knjinic (razen iz privzete standardne). V primeru ko prevajamo program v druganih okoliinah, je uporaba prevajalnika nekoliko drugana. V predhodnjem primeru smo prevajalnik uporabili za izdelavo navadne izvajalne datoteke, ki se izvaja v ukaznem oknu (ne uporablja okenskega uporabnikega vmesnika). Izdelava navadna izvajalne datoteke je privzeti nain delovanja prevajalnika. Druge izhodne formate lahko pri prevajanju doloimo z uporabo stikala /target, ki doloa format izhodne datoteke. Mone izbire pri uporabi tega stikala so: /target:exe /target:winexe /target:library /target:module prevod v navadno (terminalsko) izvajalno datoteko prevod v okensko izvajalno datoteko prevod v dinamino knjinico (DLL) prevod v modul brez manifesta

Prva izbira je e opisan privzeti nain prevajanja. Drugi izbira pri uporabi stikala /target je namenjena prevajanju okenskih aplikacij. V obeh primerih mora v izvorni kodi obstajati vsaj ena metoda Main, ki predstavlja vhodno toko pri zagonu programa. Nekoliko drugaen rezultat nam omogoa uporaba stikala /target:library, ki povzroi prevod izvorne kode v dinamino knjinico. V tem primeru bo prevajalnik namesto izvajalne datoteke (EXE) ustvaril dinamino knjinico (DLL). Poglejmo si primer, pri katerem iz izvorne datoteke DrugiDel.cs izdelamo dinamino knjinico DrugiDel.dll: csc /target:library DrugiDel.cs Zadnja monost pri uporabi stikala /target je redko uporabna. Z uporabo stikala /target:module doseemo prevod v poseben modul, ki ne vsebuje manifesta in zato ne more biti samostojno naloen v izvajalno okolje, kot ostali izhodni formati (exe in dll). Namesto prikazane dolge navedbe stikala /target lahko uporabimo tudi krajo obliko /t. Torej bi lahko gornje prevajanje v dinamino knjinico zagnali tudi bolj prirono: csc /t:library DrugiDel.cs

2.8.3 Vkljuevanje knjinic


Vsak uporaben program v C# uporablja podatkovne tipe ali predmete, ki so definirani izven tega programa. Na primer ob uporabi programskega stavka: System.Console.WriteLine("Hello"); uporabljamo statino metodo WriteLine, ki pripada razredu Console (ki je definiran v imenskem prostoru System), ki ni del naega programa. Njegova

41

OSNOVE C#

definicija se v resnici nahaja v standardni knjinici mscorlib.dll, ki definira celoten imenski prostor System. Pri vsakem prevajanju potrebuje prevajalnik tudi dostop do podatkov o uporabljenih zunanjih tipih in predmetih. e uporabljamo le tipe ali predmete iz standardne knjinice, potem nam o tem ni potrebno posebej skrbeti, saj je privzeto standardna knjinica mscorlib.dll vkljuena v proces prevajanja. Drugae pa je v primeru, ko uporabljamo tipe ali predmete iz drugih knjinic. V tem primeru moramo pri prevajanju navesti ime knjinice, kjer so ti tipi ali predmeti definirani. To nam omogoa stikalo /reference ali kraja /r. Oglejmo si primer vkljuitve zunanje knjinice v proces prevajanja: csc /reference:DrugiDel.dll PrviDel.cs

42

OSNOVE C#

3 RAZREDI IN PREDMETI

3.1 Osnove predmetno usmerjenega programiranja


Razredi in predmeti so osnovni koncept predmetno usmerjenega programiranja. Razredi nam predstavljajo podatkovni tip in nam sluijo za abstraktni opis informacijskega problematike. Predmet predstavlja "vrednost", ki ustreza nekemu razrednemu tipu in nam sluijo za opis konkretnih stanj. Pravimo, da so predmeti izvodi (instance) razredov. Predmete ustvarimo z operatorjem new: MojRazred sklicNaPredmet = new MojRazred(); Ko govorimo o predmetno usmerjenem programiranju so zelo pomembni trije temeljni principi, ki nas vodijo pri nartovanju in izgradnji predmetno usmerjenih programov: dedovanje, enkapsulacija , polimorfizem.

3.1.1 Dedovanje
Dedovanje je definicija novega tipa, ki temelji na obstojeem tipu. Pri tem navadno definiramo nov specializiran tip, ki temelji na obstojeem splonejem tipu. Dedovanje omogoa, da starevski tip le povzamemo in ga neposredno ne spreminjamo. class NewClass : OldClass, Interface1, Interface2 { // DEFNICIJA RAZREDA: // ... LE NADGRADNJA IN RAZLIKE // ... GLEDE NA STAREVSKE TIPE

43

OSNOVE C#

} V C# lahko dedujemo le po enem razredu, lahko pa imamo ve starevskih vmesnikov.

3.1.2 Enkapsulacija
Enkapsulacija je princip, ko v enoto zdruimo podatke in kodo, ki operira nad temi podatki. Pri tem nam kot ovojnica slui ravno razred. Drugi pomemben koncept enkapsulacije pa je skrivanje izvedbenih podrobnosti. Notranji podatke in procese navzven skrijemo, saj je za uporabnika razreda pomemben samo tisti del razreda, ki smo ga za to posebej doloili. Razredi v C# omogoajo zdruevanje podatkov in kode z naslednjimi razrednimi lani: lanske spremenljivke (fields) in konstante, metode, lastnosti in indekserji, dogodki, operatorji konstruktorji in destruktorji vgnezdeni tipi.

Oglejmo si primer razreda z vsemi natetimi lani: class MyClass { public MyClass() { Console.WriteLine("Instance constructor"); } public MyClass(int value) { MyField = value; Console.WriteLine("Instance constructor"); } ~MyClass() { Console.WriteLine("Destructor"); } public const int MyConst = 12;

44

OSNOVE C#

public int MyField = 34; public void MyMethod() { Console.WriteLine("MyClass.MyMethod"); } public int MyProperty {

get {return MyField;} set {MyField = value;} } public int this[int index] { get {return 0; } set {Console.WriteLine("this[{0}] = {1}", index, value);} } public event EventHandler MyEvent; public static MyClass operator+(MyClass a, MyClass b) { return new MyClass(a.MyField + b.MyField); } internal class MyNestedClass {} } lane, ki sestavljajo razred lahko skrivamo s pridevniki za dostopnost, ki lahko nastopajo kot sestavni del deklaracij razrednih lanov. Pri tem lahko uporabimo naslednje pridevnike za dostopnost: private (dostopno znotraj tipa) protected internal (dostopno znotraj projekta in otrok) internal (dostopno znotraj projekta) protected (dostopno znotraj razreda in otrok) public (vsem dostopno)

45

OSNOVE C#

3.1.3 Polimorfizem
Polimorfizem je princip, ko lahko uporabljamo razline tipe na isti nain. To pomeni, da lahko upravljam z razlinimi predmeti na doloen in znan nain, ne da bi natanko vedel kaknega tipa so. Predmeti se bodo ob tem vedli, kot je za vsakega od njih ustrezno (in ne vsi enako). V C# lahko doseemo polimorfizem z dedovanjem razlinih tipov iz skupnega razreda ali iz skupnega vmesnika skupaj s preoblaganjem metod in operatorjev. Polimorfizem nam prikazuje naslednji del C# kode: static void Main() { Toka t1 = new Toka(1,2); Avto a1 = new Avto(Barva.Rdea); IIzpisljivo[] predmeti = new IIzpisljivo[2];

predmeti[0] = t1; predmeti[1] = a1;

foreach (IIzpisljivo predmet in predmeti) { predmet.Izpii(); } } // NE ZANIMA ME NATANEN TIP // KER VEM, DA SE VEDE KOT JE PRAV

3.2 lani razreda


3.2.1 lanske konstante in spremenljivke
Tako lanske konstante kakor tudi spremenljivke lahko pripadajo razredom ali izvodom. V prvem primeru so deklarirane s pridevnikom static, v drugem pa brez tega pridevnika. class Zaposlen

46

OSNOVE C#

{ public const int teviloNarno = 2000; internal string ime; } //pripada izvodom static int teviloZaposlenih; //pripada razredu

3.2.2 Metode
Metode so aktivni lani razredov. To so funkcije, ki pripadajo razredu ali izvodom. V prvem primeru so deklarirane s pridevnikom static, v drugem pa brez tega pridevnika. Metode imajo doloen vraajoi tip in seznam argumentov, ki jih sprejmejo. Metode lahko preoblagamo. To pomeni, da se lahko enako imenovana metoda pojavlja v razredu v ve razliicah, ki se morajo med seboj razlikovati po seznamu argumentov, lahko pa se razlikujejo tudi po telesu (kar je smiselno). class Zaposlen { public const int teviloNarno = 20; internal string ime; static int teviloZaposlenih; void F() { //... } void F(int i) {// metodo F smo preobloili //... } } // metoda F brez argumentov

3.2.3 Lastnosti
Lastnost (property) je krianec med spremenljivko in metodo. Lastnosti so navzven vidne kot spremenljivke saj jih v izrazih in pri prirejanjih uporabljamo kot obiajne spremenljivke. Pri vsakem dostopu (ko jih beremo ali vanje piemo) pa se v resnici izvede koda, ki jo definiramo. Notranja izvedba uporablja metodami get in set. Pri tem mora metoda get vrniti neko vrednost, ki je istega tipa kot lastnost. Metoda set ima pri svojem delu na razpolago implicitni parameter value, ki predstavlja vrednost, ki smo jo priredili lastnosti. Metodi get ali set (vsako posebej) lahko izpustimo. Na tak nain dobimo write-only ali read only lastnosti.

public class Button {

47

OSNOVE C#

private string caption; public string Caption { get { return caption; } set { caption = value; Repaint(); } } }

3.2.4 Indekserji
Indekser (indexer) je raziritev lastnosti. Z njegovo pomojo lahko iz vsakega razreda izgradimo indeksiran vsebovalnik (container), ki ga bomo lahko uporabljali kot obiajna polja. e ve: taken vsebovalnik bomo lahko uporabljali z indeksom, ki je poljubnega tipa. Uporaba tako izgrajenih vsebovalnikov se navzven ne razlikuje od vgrajenih. class Flota { public Ladja[] zbirka = new Ladja[10]; public int this[int index] { get {return zbirka[index].Prostornina;} } public int this[string ime] { get { foreach (Ladja ladja in zbirka) {

48

OSNOVE C#

if (ladja!=null && ladja.Ime.Equals(ime)) return ladja.Prostornina; } return 0; } } } class AllTogether { static void Main() { Ladja ladja1 = new Ladja("Barica",10); Ladja ladja2 = new Ladja("Barkaa",50);

Flota flota = new Flota(); flota.zbirka[0] = ladja1; flota.zbirka[1] = ladja2;

System.Console.WriteLine(flota[0]); System.Console.WriteLine(flota[1]);

System.Console.WriteLine(flota["Barkaa"]); System.Console.WriteLine(flota["Barica"]); } }

49

OSNOVE C#

3.2.5 Operatorji
Preobloimo lahko veino operatorjev kot so aritmetini, primerjalni, logini in bitni operatorji. Ne moremo pa preobloiti prirejanja in operatorjev kot so sizeof, new in is. Poglejmo si primer preoblaganja operatorjev: public static Ulomek operator +(Ulomek a, Ulomek b) { return new Ulomek(a.num * b.den + b.num * a.den, a.den * b.den); }

3.2.6 Dogodki
J# omogoa podpora dogodkom e na nivoju samega jezika. Kljuna beseda event nam omogoa doloiti delegata, ki bo ustrezal poklicanim metodam ob nastopu nekega dogodka. public event AlarmEventHandler Alarm; Dogodek sproimo s klicem dogodka Alarm(); Odjemalci se prijavijo na dogodek z operatorjem += eventSource.Alarm += new AlarmEventHandler(eventListener.AlarmRang);

3.2.7 Konstruktorji
Konstruktorji so posebne metode, ki se pokliejo ob ustvarjanju predmeta ali ob ustvarjanju razreda (v tem se C# razlikuje od sorodnih jezikov). Dve vrsti konstruktorjev sta: konstruktorji izvodov in statini konstruktorji. Konstruktorji izvodov so klasini kostruktorji kakrne poznamo pri sorodnih programskih jezikih. Ti definirajo kaj je potrebno storiti ob ustvarjanju izvoda (predmeta). Konstruktorji izvodov so metode, ki se imenujejo kot razred in nimajo vraajoega tipa. Ti konstruktorji so lahko so preobloeni. Statini konstruktor definira kaj je potrebno storiti ob ustvarjanju razreda. Ta konstruktorji je statina metoda z imenom razreda, ki nima vraajoega tipa, je brez argumentov in nima pridevnikov za dostop. class Zaposlen { public const int teviloNarno = 20; internal string ime; static int teviloZaposlenih;

50

OSNOVE C#

public Zaposlen() { this.ime = "neznano"; teviloZaposlenih++; } public Zaposlen(string ime) { this.ime = ime; teviloZaposlenih++; } static Zaposlen() { teviloZaposlenih = teviloNarno; } }

3.2.8 Destruktor
Destruktor je metoda, ki se izvede ob unienju predmeta. Destruktorja poklie smetar, ko se odloi odstraniti predmet. Destruktor je metoda z imenom razreda ter znakom ~ pred njim, ki nima vraajoega tipa, je brez argumentov in nima pridevnikov za dostop. class Zaposlen { // ... ~Zaposlen() { Console.WriteLine("Unien!!!"); } }

51

OSNOVE C#

4 IZBRANA DODATNA POGLAVJA

4.1 Rokovanje z izjemami


V jeziku C# delamo z izjemami na enak nain kot ostali sorodni programski jeziki. V ta namen uporabljamo naslednji jezikovni konstrukt: try {...} catch () {...} finally {...} V prvem delu (try) se nahaja koda, pri kateri se lahko sproi izjema. e se to zgodi, potem prevzame kontrolo catch blok. V tem bloku servisiramo napako. Neobvezno lahko gornjima dvema stavkoma dodamo e finally blok. Ta se bo izvedel kot zadnji od treh blokov in sicer v vsakem primeru, ne glede na to ali je v try bloku prilo do napake ali ne. Izjeme proimo lahko tudi sami z uporabo kljune besede throw. static int F(int a, int b) { if (b == 0) throw new Exception("Deli z 0"); return a / b; } static void Main() { try { Console.WriteLine(F(5, 0));

52

OSNOVE C#

} catch(Exception e) { Console.WriteLine("Napaka"); } finally {Console.WriteLine("End");} }

4.2 Boxing in unboxing


V C# je mono spreminjati poljuben vrednostni tip v sklicnega in spet nazaj. Temu postopku pravimo boxing in unboxing. Boxing torej uporabljamo, ko pri vrednostnih tipih potrebujemo sklic. To se lahko zgodi na primer takrat, ko elimo imeti polje, ki bi hranilo vse raznovrstne vrednosti. Tako polje mora hraniti sklice na najbolj osnovni razred object. e elimo polju dodati vrednosti enostavnih tipov (na primer int) jih moramo pretvoriti v sklicni tip.

int value; object boxedValue = value; //boxing value = (int)boxedValue; //unboxing

4.3 Pretvorbe med tipi


Pretvorbe med tipi so lahko dveh vrst: implicitne pretvorbe eksplicitne pretvorbe

Implicitna pretvorba se izvede brez posebne zahteve s strani programerja. Mona je le e ne pride do izgube pri pretvorbi. Na primer pretvorba iz tipa int v long, ne pa tudi obratno. Implicitna pretvorba je tudi pretvorba sklicnega tipa otroka v sklicni tip (pra)stara. long tevilo = 123; Eksplicitna pretvorba je tista, ki je izrecno zahtevana. Eksplicitne pretvorbe so numerine pretvorbe med vsemi tipi. Eksplicitno pretvorbo zahtevamo z operatorjem (tip)izraz. double x = 1234.7; int a; a = (int)x;

53

OSNOVE C#

Mone so tudi uporabniko doloene pretvorbe med poljubnimi tipi. V ta name uporabimo besedi implicit in explicit.

4.4 Smetar
V jeziku C# programerju ni potrebno skrbeti za sproanje pomnilnika, ki ga zasedajo predmeti, ki jih ve ne potrebujemo. Za njih poskrbi smetar (garbage collector). Smetar upravlja s kopico na kateri se nahajajo predmeti in polja. Smetar je aktiven le obasno, saj ne poisti za vsakim odvenim predmetom posebej, temve poaka in poisti ve "smeti" naenkrat. Smetar upravlja tudi z veljavnimi predmeti in jih premika po pomnilniku, ko defragmentira kopico. Smetar prinaa s seboj tudi nekaj slabosti. Zaradi nedeterministinega sproanja predmetov se ne smemo zanaati na destruktor. Zato raje uporabljajmo eksplicitno sproanje z izvedbo Dispose(). Prav tako nam lahko smetar povzroa probleme zaradi premikanja predmetov po pomnilniku. Zato moramo v primeru dela s kazalci zafiksirati predmete s katerimi delamo. Poglejmo si tak primer. class Test { unsafe static void IzpiiPoloaj(byte[] arr) { fixed (byte *pArray = arr) { byte *pElem = pArray; for (int i = 0; i < arr.Length; i++) { byte value = *pElem; Console.WriteLine("{0} {1} {2}",i,(uint)pElem,value); pElem++; } } } static void Main() { byte[] arr = new byte[] {1, 2, 3, 4, 5}; IzpiiPoloaj(arr); } }

54

OSNOVE C#

4.5 Atributi
Podobno kot to velja za pridevnike (na primer public, private ...) , so tudi atributi deklarativni elementi jezika. Atributi posploujejo koncept deklarativnega elementa saj niso omejeni na vnaprej doloeno mnoico. S pomojo mehanizma atributov si lahko programer zamisli svoje nove atribute. Atributi in njihove vrednosti so dosegljivi v asu prevajanja in v asu izvajanja. [Obsolete("This class is obsolete")] class A { public void F() {} }

4.6 XML dokumentacijski komentarji


Poleg "navadnih" komentarjev, lahko programsko kodo v C# opremimo tudi z XML dokumentacijskimi komentarji. Njihov namen uporabe je avtomatska izdelava dokumentacije pri delu na velikih projektih. Dokumentacijski komentar oznaujejo tri poevnice: ///. Dokumentacijski komentarji temeljijo na XML-u, ob tem pa nam C# nudi e standardno shemo za XML dokumentacijske komentarje.

///<summary> /// vedno vrne 0 ///</summary> public int doIt() { return (0); } Dokumentacijke komentarje lahko avtomatino pretvorimo v dokumentacijo s prevajanjem ob uporabi stikala /doc.

55

OSNOVE C#

5 LITERATURA

Microsoft Visual Studio .NET MSDN Library, msdn.microsoft.com, Microsoft Corporation, 2001 C# and the .NET Platform Publisher, APress, ISBN: 1893115593, 1st edition, 2001 C# Unleashed Publisher, Sams, ISBN: 067232122X, 1st edition, 2002 Microsoft MSDN Magazine, Corporation, Issues 2001 2002 Visual Studio .NET Magazine, Publications, Issues 2001 2002 msdn.microsoft.com/msdnmag, www.fawcette.com, Fawcette Microsoft Technical

.NET Community WebSite, www.gotdotnet.com, Microsoft Corporation, 2002

56

OSNOVE C#

todo: 1. kaj so lahko pridevniki 2. uredi razlikovanje med predmetom in izvodom 3. preveri delovanje kode 4. definicija -> deklaracija ??? 5. komentarji naj bodo z velikimi rkami 6. I/O - pisanje, branje, datoteke, ...

57

You might also like