Professional Documents
Culture Documents
Programiranje C#
Jesse Liberty
Prijevod:
Ana Anti
Marko Grgi
E x p e rt
IT
0 REILLY
Programiranje C#, prijevod
etvrtog izdanja
Jesse Liberty
CIP - Katalogizacija u
publikaciji Nacionalna i
sveuilina knjinica -
Zagreb
LIBERTY, Jesse
Programiranje C#
/ Jesse
liberty ; prijevod Ana Anti, Marko
Grgi.
- Zagreb : Dobar Plan, 2005.
I5BN 953-95207-1-1
I. C# programski jezik --
Prirunik 451124026
L J
ISBN 953-95207-1-1 3 2 1
Sadraj
Predgovor ........................................................................ ix
Dio I JezikC#
1. ProgramskijezikC#i.NETkostur .......................................... 3
Platforma .NET 3
.NET kostur 4
Prevoenje i MSIL 6
Jezik C# 6
2. Poetak:HelloVVorld" ............................................................. 9
Klase, objekti i tipovi 9
Razvoj programa Hello World 16
Koritenje programa za ispravljanje pogreaka 20
3. Osnove programskog jezika C # ............................................... 23
Tipovi 23
Varijable i konstante 28
Izrazi 35
Bijeli prostor 36
Iskazi 37
Operatori 52
Naredbe za pretprocesor 60
4. Klase i objekti ............................................................... 64
Definiranje klasa 65
Stvaranje objekata 70
Koritenje statikih lanova 77
Unitavanje objekata 81
Prosljeivanje parametara 84
Preoptereivanje metoda i konstruktora 90
Uahurivanje podataka sa svojstvima 93
Polja readonly 97
5. Nasljeivanje i polimorfizam ............................................. 99
Specijalizacija i generalizacija 99
Nasljeivanje 102
Apstraktne klase 109
Korijen svih klasa: Object 113
Pakiranje i raspakiravanje tipova 115
Ugnjeivanje klasa 117
6. Preoptereivanje operatora ................................................120
Koritenje kljune rijei operator 120
Podrka ostalim .NET jezicima 121
Stvaranje korisnih operatora 121
Logiki parovi 122
Operator jednakosti 122
Operatori pretvaranja 123
7. Strukture ............................................................................129
Definiranje struktura 129
Stvaranje struktura 132
8. Suelja ........................................................................ 136
Definiranje i implementiranje suelja 137
Pristupanje metodama suelja 145
Premoivanje implementacija suelja 153
Eksplicitna implementacija suelja 156
9. Polja, indekseri i kolekcije .................................................... 166
Polja 166
Iskaz foreach 171
Inicijaliz'iranje elemenata polja 172
Indekseri 184
Suelja kolekcija 193
Ogranienja 196
vi | Sadraj
List<T> 201
Redovi 212
Stogovi 214
Rjenici 217
10. Nizovi i regularni izrazi ........................................................ 220
Nizovi 221
Regularni izrazi 235
11. Obrada izn im k i ........................................................................ 245
Izbacivanje i hvatanje iznimki 246
Objekti Exception 255
Prilagoene iznimke 258
Ponovno izbacivanje iznimki 261
Sadraj | vii
Povezivanje podataka 367
Web usluge 377
SOAP, WSDL i otkrivanje 377
Izrada Web usluge 378
Stvaranje posrednika 383
16. Sastavljanje u cjelinu .......................................................... 389
Ukupni dizajn 389
Izrada klijenta Web usluge 389
Prikazivanje rezultata 399
Pretraivanje po kategorijama 408
viii | Sadraj
21. Tokovi p o d a ta k a ............................................... 491
Datoteke i mape 492
itanje i upisivanje podataka 502
Asinkroni ulaz i izlaz 510
Ulaz i izlaz podataka preko mree 514
Web tokovi 533
Serijalizacija 536
Izolirano spremite 544
22. .NET i COM programiranje .............................. 548
Uvoenje ActiveX kontrola 548
Uvoenje COM komponenata 556
Izvoenje .NET komponenata 564
P/Invoke 567
Pokazivai 570
Dodatak: C# kljune rijei.......................................................... 575
Sadraj | ix
Predgovor
Otprilike svakih deset godina pojavi se nova tehnologija koja promijeni na stav prema
razvoju aplikacija. Poetkom 1980-ih pojavio se operacioni sustav Unix koji se mogao
pokrenuti na stolnom raunalu, a tvrtka AT&T razvila je moan novi programski jezik
C. Poetkom 1990-ih pojavio se operativni sustav Windows i jezik C++. Svaka nova teh-
nologija predstavljala je veliku promjenu u pristupu programiranju. 2000. godine uslije-
dio je novi val koji je donio .NET i C# , a do kraja 2005. godine donjet e i .NET 2.0.
Microsoft se kladio 1 na .NET. Kada tako velika i utjecajna tvrtka potroi milijarde
dolara i promijeni cjelokupnu strukturu poduzea kako bi podravala novu platformu,
to ne ostaje nezapaeno meu programerima. .NET e ustvari promijeniti va stav
prema programiranju. Ukratko, radi se o novoj razvojnoj platformi ija je svrha olakati
objektno orijentiran razvoj za Internet. Programski jezik koji je izabran za ovu plat-
formu je C# , smiljen na temelju ranijeg iskustva sa jezicima C (odline performanse),
C++ (objektno orijentirana struktura), Java (sakupljanje otpada, visoka razina sigur-
nosti) i Visual Basic (brz razvoj), s namjerom stvaranja novog jezika koji e u potpuno-
sti odgovarati vieslojnim Web aplikacijama temeljenim na komponentama.
C# 2.0, jezik odabran za .NET 2005, sadri aurirane alate i novi snani razvojni oko-
li. On predstavlja najvee dostignue Microsoftovog ulaganja u istraivanje i razvoj.
Jednostavno je sjajan.
0 knjizi
Ova knjiga je prirunik za C# i pisanje .NET aplikacija s pomou jezika C# .
Ako ste programer koji se dobro slui jezikom C# 1.1 i samo elite saznati koje su nove
znaajke jezika C# 2 .2 , odloite ovu knjigu i kupite Visual C# 2005: A Developers
Notebook (u izdanju 0 Reilly Media, Ine.).
Ako, s druge strane, elite poboljati svoje vjetine programiranja ili se dobro sluite
drugim programskim jezicima kakvi su C++ ili Java, ak i ako se nikad niste upoznali
s drugim programskim jezikom, ovo je prava knjiga za vas.
xi
to vam treba za koritenje ove knjige
Od beta izdanja programa Visual Studio Whidbey (2005) pristup radovima tvrtke
Microsoft mnogo je jednostavniji. Dostupno vam je nekoliko mogunosti: ba kao to
Visual Studio ima mnogo inaica, tako su i demo inaice .NET-a 2 .0 i Visual Studija
2005 dostupne u razliitim oblicima:
Preuzimanje SDK
Beta SDK, zajedno s prevoditeljima za pokretanje u naredbenom redu, dokumen-
tacijom i drugim alatima, moe se besplatno preuzeti na adresi http://msdn.micm-
soft.com/netframework/downloads/updates/default.aspx. Datoteka za preuzimanje
nije velika, ali bit e vam potreban vlastiti program za ureivanje koda (moete
koristiti bilo koji, od Notepada do SharpDevelopera).
Express izdanja
Microsoft je izdao i ogoljene inaice platforme Visual Studio koje su male pa ih
lako moete preuzeti s Internetra i pokrenuti. Express inaice moete preuzeti
na adresi http://lab.msdn.microsoft.com/vs2005. Za veinu primjera iz ove knjige
koristite Visual C # Express. Za neke primjere bit e vam potreban Visual Web
Developer Express, a za neke ADO.NET primjere morat ete instalirati SQL Ser-
ver Express ili MSDE (Microsoft Data Engine).
Beta i Community Tech Preview
Pune inaice platforme Visual Studio 2005 dostupne su za preuzimanje u dva for-
mata: Community Technology Preview (CTP) koji djeluje pomalo nedovreno te
potpuno beta izdanje. U vrijeme pisanja ove knjige, CTP formati bili su dostupni
MSDN pretplatnicima na Visual Studio Professional, Standard i Team Systems.
Beta 1 inaica Visual Studija Professional takoer je dostupna MSDN pretplat-
nicima, a ostali plaaju samo trokove potarine. Vie informacija potraite na
http://lab.msdn.microsoft.com/vs2005lgetldefault.aspx.
Mono
Projekt Mono je razvojna platforma otvorenog izvornog koda koja se temelji na
.NET-u. Sponzorira ju tvrtka Novell, a moe se koristiti na operativnim sustavima
Linux, Mac OS X i drugima. Iako je trenutna inaica namijenjena za .NET 1.1,
moete ju instalirati s podrkom za neke .NET 2 .0 znaajke. Vie informacija
potraite na http://www.mono-project.com/about/index.html.
etvrto izdanje Programiranja C# moete koristiti za sve navedene okolie. Slike zaslona
mogu se, meutim, razlikovati jer je svaki od ovih okolia u drugoj inaici.
xii | Predgovor
Dio I, Jezik C#
Poglavlje 1, Programski jezik C# i.NET kostur predstavlja uvod ujezik C# i platformu
.NET.
Poglavlje 2, Poetak: Hello World opisuje jednostavan program kao uvod u sljedea
poglavlja te vam predstavlja Visual Studio IDE i razne koncepte jezika C# .
U Poglavlju 3, Osnove programskog jezika C# , opisane su osnove jezika, od ugraenih
tipova podataka do kljunih rijei.
Klase definiraju nove tipove i programeru omoguuju proirivanje jezika kako bi bolje
mogao oblikovati problem koji pokuava rijeiti. U Poglavlju 4, Klase i objekti, opisane
su komponente koje ine bit jezika C# .
Klase mogu biti kompleksna predoenja i apstrakcije pojava iz stvarnog svijeta. Pogla-
vlje 5, Nasljeivanje i polimorfizam, bavi se odnosima izmeu klasa.
U Poglavlju 6, Preoptereivanje operatora, moete nauiti kako svojim korisniki defi-
niranim tipovima moete dodati operatore.
Poglavlja 7 i 8 su uvod u Strukture i Suelja, kategorije srodne klasama. Strukture su
jednostavni objekti koji su neto ogranieniji od klasa, a manje su zahtjevni za opera-
tivni sustav i memoriju. Suelja su poput ugovora - opisuju kako e klasa funkcionirati
tako da drugi programeri mogu koristiti vae objekte na dobro definiran nain.
Objektno orijentirani programi mogu stvoriti veliki broj razliitih objekata. esto ih je
prikladno grupirati i s njima zajedniki raditi, a C# prua opsenu podrku za kolek-
cije. U Poglavlju 9, Polja, indekseri i kolekcije, opisane su klase kolekcija koje prua
Framevvork Class Library, nove generike kolekcije i nain na koji programeri mogu
stvarati vlastite tipove kolekcija s pomou generika.
Poglavlje 10, Nizovi i regularni izrazi, opisuje nain upotrebe jezika C# za rad s tekstu-
alnim nizovima i regularnim izrazima. Veina Windows i Web programa komunicira
s korisnikom, a nizovi imaju kljunu ulogu u korisnikom suelju.
U Poglavlju 11, Obrada iznimki, objanjeni su postupci obrade iznimki koji pruaju
objektno orijentiran mehanizam za rjeavanje moguih hitnih sluajeva".
I Windows i Web aplikacije reagiraju na dogaaje. U jeziku C# dogaaji su vani
lanovi jezika. Poglavlje 12, Delegati i dogaaji posveeno je nainu obrade dogaaja i
koritenju delegata (objektno orijentiranih mehanizama povratnih poziva koji su
sigurni za tip) kao podrke za obradu dogaaja.
Predgovor | xiii
Na vrhu .NET infrastrukture nalazi se apstrakcija operativnog sustava ija je svrha
da olaka razvoj objektno orijentiranog softvera. U ovaj gornji sloj pripadaju i ASP.
NET i Windows Forms. ASP.NET ukljuuje Web Forms za brzi razvoj Web aplikacija
i Web usluge za izradu Web objekata bez korisnikog suelja. Web usluga je distribui-
rana aplikacija koja prua funkcionalnost preko standardnih Web protokola, najee
XML-a i HTTP-a.
C# prua model brzog razvoja aplikacija koji je dosad postojao samo u jeziku Visual
Basic. Poglavlje 13, Programiranje Windows aplikacija, opisuje nain koritenja RAD
modela za stvaranje Windows programa profesionalne kvalitete s pomou razvojnog
okolia Windows Forms.
Bez obzira jesu li namijenjene za Web ili klasini operacioni sustav, veina aplikacija se
temelji na obradi velike koliine podataka. Poglavlje 14, Pristup podacima kroz ADO.
NET, objanjava ADO.NET sloj u .NET kosturu i nain interakcije s Microsoft SQL
posluiteljem i ostalim izvorima podataka.
Predmet poglavlja 15, Programiranje ASP.NET aplikacija i Web usluga, su dva dijela
ASP.NET tehnologije: Web Forms i Web Services.
U Poglavlju 16, Sastavljanje u cjelinu, kombinira se velik broj vjetina obraenih u dru-
gom dijelu kako biste nauili razvijati skup integriranih aplikacija.
Dio III,CLRi.NETkostur
Izvedbeni okoli je sredina u kojoj se izvode programi. Common Language Runtime
(CLR) je sr platforme .NET. On sadri sustav tipizacije podataka koji se primjenjuje
na cijeloj platformi i koji je zajedniki svim jezicima koje.NET podrava. CLR je odgo-
voran za postupke poput upravljanja memorijom i brojanja referenci objekata.
Druga kljuna znaajka .NET CLR-a je sakupljanje otpada. Za razliku od tradicional-
nog C/C++ programiranja, u jeziku C# programer nije odgovoran za unitavanje obje-
kata. Beskrajni sati provedeni u traenju objekata koji se vie ne koriste sada su stvar
prolosti. Kada se objekti vie ne koriste, CLR e za vama obaviti ienje. Metoda
sakupljanja otpada u CLR-u provjerava ima li u gomili objekata bez referenci i oslo-
baa memoriju koju ti objekti zauzimaju.
Platforma .NET i biblioteka klasa proiruju se prema viim razinama sve do platforme
srednje razine na kojoj se nalazi infrastruktura klasa za podrku, zajedno s tipovima
za komunikciju izmeu procesa, XM L, rad s dretvama, ulaz i izlaz podataka, zatitu,
dijagnostiku itd. Srednji sloj sadri i komponente za pristup podacima koje se skupno
nazivaju ADO.NET.
U treem dijelu ove knjige obraen je odnos izmeu jezika C# , CLR-a i biblioteke
klasa kostura.
xiv | Predgovor
U Poglavlju 17, Sklopovi i rad s inaicama, opisane su razlike izmeu privatnih i javnih
sklopova te nain stvaranja i rada sa sklopovima. Na platformi .NET sklop je skup
datoteka koji korisniku izgleda kao jedinstvena DLL ili izvedbena datoteka. Sklop je
osnovna jedinica za ponovnu upotrebu, rad s inaicama, zatitu i primjenu.
.NET sklopovi sadre iscrpne metapodatke o klasama, metodama, svojstvima, doga-
ajima i ostalim elementima. Oni se prevode u program i automatski dohvaaju kroz
refleksiju. U Poglavlju 18, Atributi i refleksija, objanjeno je dodavanje metapodataka
u kod, stvaranje prilagoenih atributa i pristup metapodacima s pomou refleksije.
U ovom poglavlju moete pronai i informacije o dinamikom pozivanju pri kojem se
metode pozivaju sa kasnim povezivanjem.
Predgovor | xv
Ako ste prethodno radili s jezicima C, C++, VB 6 ili Java, u sljedeim odjeljcima
moete pronai usporedbu osnovnih svojstava tih jezika s jezikom C# . U cijeloj knjizi
postoje napomene posebno napisane za vas.
C# u usporedbi s Javom
Java programeri e na C# vjerojatno gledati s mjeavinom osjeaja strepnje, veselja i
ogorenosti. Postoji miljenje da je C# kopija" jezika Java. Ne bih htio komentirati
vjerski rat izmeu Microsofta i onih koji mu nisu naklonjeni. Jedino u napomenuti
kako je jezik C# mnogo toga nauio od jezika Java, ali je i Java mnogo toga nauila
od C++, koji je svoju sintaksu preuzeo od jezika C, a C je izgraen po uzoru na starije
programske jezike. Svi mi stojimo na ramenima divova.
C# Java programerima nudi jednostavan prijelaz: sintaksa je vrlo slina, a semantika
je poznata i jednostavna. Java programeri e se za uinkovito koritenje jezika C#
vjerojatno morati usredotoiti na razlike izmeu ta dva jezika. U knjizi sam te razlike
pokuao dodatno istaknuti (pogledajte napomene za Java programere u poglavljima).
xvi | Predgovor
C# u usporedbi sjezikom C ++
Programiranje na jezicima C i C++ za platformu .NET je mogue, no nije jednostavno
niti prirodno. Iskreno, deset sam godina radio kao C++ programer, napisao sam dese-
tak knjiga o njemu i radije bih otiao zubaru nego radio s upravljanim C++. Moda
se radi samo o tome da je C# mnogo jednostavniji. U svakom sluaju, nakon to sam
poeo koristiti C# , vie se nisam osvrtao.
Meutim, budite paljivi: postoji mnogo malih zamki koje sam nastojao vidljivo oznaiti.
Predgovor | xvii
Podrka
Kao autor, prua m stalnu podrku za svoje knjige na Web stranici ija je adresa:
http://www.LibertyAssociates.com
Na toj stranici moete preuzeti i izvorni kod za sve primjere iz knjige Programiranje
C#. Tamo ete moi pristupiti forumu o knjizi s posebnim dijelom za pitanja u vezi s
jezikom C#. Prije postavlja nja pitanja proitajte FAQ i datoteke s ispravka ma. Ako i
na kon to proitate te dokumente jo uvijek imate pitanje, postavite ga na forumu.
Najuinkovitiji nain za dobiva nje pomoi je postavlja nje vrlo preciznog pitanja ili
ak pisa nje kratkog progra ma koji ilustrira podruje koje vas zanima ili zabrinjava.
Korisno je iprovjeriti razliite diskusijske grupe i forume na Internetu. Microsof t nudi
irok raspon diskusijskih grupa, a DevelopMentor (http://discuss.develo p.com) odrava
iznimno korisan e-mail foru m.
Zahvale
Prije nego to nastavim, moram se posebno zahvaliti lanu Griffithsu koji je temeljito
recenzirao tekst i dao strune savjete. Ubraja se u skupinu ugodnijih i pametnijih ljudi
s kojima suraujem.
Ovo je etvrto izdanje knjige i previe mi je prijatelja i itatelja pomoglo unaprijediti ju
da bi ih mogao sve nabrojati. Ali, posebno mora m spomenuti sljedee osobe: Donald
Xie, Dan Hurwitz, Seth Weiss, Sue Lynch, Cliff Gerald, Tom Petr, Jim Culbert, Mike
Woodring, Eric Gu nnerson, Rob Howard, Piet Obermeyer, Jonathan Hawkins, Peter
Drayton, Braci Merrill, Ben Albaha ri, Susan Warren, Bram Bischof i Kent Quirk.
John Osborn omoguio mi je suradnju s izdavakom kuom O'Reilly, za to u mu
uvijek biti zahvalan. Valerie Quercia, Claire Cloutier i Tatiana Diaz napravile su velik
posao na prethodnim inaica ma, a nadogradnju na C# 2.0 predvodio je Brian Jepson.
Rob Romano je izradio brojne nove ilustracije i poboljao stare. Tim O'Reilly je pruio
podrku i resurse i za to sam mu zahvalan.
Javili su mi se m nogi itatelji i obavijestili nas o pravopisnim i manjim pogrekama
u prva tri izda nja. Vrlo smo im zahvalni, a posebno bi htio spomenuti sljedee itate-
lje: Peter Adams, Sol Bick, Brian Cassel, Steve Charbonneau, Ronal Chu, John Cor-
ner, Duane Corpe, Kevin Coupland, Randy Eastwood, Glen Fischer, Larry Fix, Andy
Gaskall, Dave Fowler, Vojimir Golem, David Kindred, Steve Kirk, Bob Kilne, Theron
LaBounty, Arnn Landy, Jeremy Lin, Chris Linton, Mark Melhado, Harry Martyros-
sian, Jason Mauss, Stephen Nelson, Harold Norris, Tim Noll, Mark Phillips, Marcus
Rahilly, Paul Reed, Christian Rodriguez, David Solum, Paul Schwartzburg, Erwing
Steininger, Fred Talmadge, Steve Thompson, Greg Torrance, Ted Volk, John Watson,
Walt White i Seen Sai Yang.
Predgovor | xix
POGLAVLJE 1
C# 2 .0 ima ulogu jezika za .NET razvoj koji e biti jednostavan, siguran, moderan,
objektno orijentiran, usmjeren na Internet i visokih performansi. C# sada je potpun
jezik i na njega su primijenjena iskustva iz tri protekla desetljea. Kao to u djeci
moete vidjeti osobine njihovih roditelja, baka i djedova, u jeziku C# lako moete
zapaziti utjecaj jezika Java, C++, Visual Basic (VB) i drugih ali i lekcije nauene od
prve pojave jezika C# .
Glavni predmet ove knjige je jezik C# i njegova upotreba kao alata za programiranje
na platformi .NET, posebno u razvojnom okoliu Visual Studio.NET 2005 (potpuna
ili Express Edition inaica).
Ako koristite Mono ili neku drugu inaicu jezika C # koju nije pro-
izvela tvrtka Microsoft, vjerojatno ete uvidjeti kako svi programi iz
ove knjige ispravno funkcioniraju, iako su testirani samo na odobrenoj
Microsoft inaici.
Platforma .NET
Kada je u srpnju 2000 . Microsoft najavio C# , njegova premijera bila je dio mnogo
veeg dogaaja: najave platforme .NET. C# 2.0 predstavlja zrelu fazu jezika i podu-
dara se s izdanjem nove generacije alata za .NET.
Platforma .NET je razvojni kostur koji daje novi API za usluge i API-je starijih inaica
operativnog sustava Windows, a istovremeno kombinira brojne razliite tehnologije
koje je Microsoft razvio tijekom kasnih 1990-ih. To ukljuuje komponentne usluge
3
COM+, posveenost XML-u i objektno orijentiranom dizajnu, podrku za nove pro-
tokole Web usluga kao to su SOAP, WSDL i UDDI te fokusiranje na Internet, a sve to
integrirano unutar arhitekture Distributed interNet Applications (DNA).
Microsoft je ogromne resurse posvetio razvoju platforme .NET i njoj srodnih tehno-
logija. Dosadanji rezultati tog rada uistinu su impresivni. Ako nita drugo, .NET je
ogromnog raspona. Platforma se sastoji od tri grupe proizvoda:
Skupa jezika, koji ukljuuje C# i VB, skupa razvojnih alata u kojem se nalazi i
Visual Studio .NET, iscrpna biblioteka klasa za izradu Web usluga te Web i Win-
dows aplikacija, kao i Common Language Runtime (CLR) za izvoenje objekata
izraenih unutar ovog kostura.
Dvije generacije posluitelja .NET Enterprise: ve objavljenih posluitelja i onih
koji trebaju biti objavljeni u sljedee dvije ili tri godine
Novih ureaja koji nisu kuna raunala, a podravaju .NET
.NET kostur
Microsoft .NET podrava ne samo neovisnost jezika, ve i integraciju jezika. To znai
da moete nasljeivati iz klasa, hvatati iznimke i iskoristiti prednosti polimorfizma u
razliitim jezicima. .NET kostur vam to omoguava kroz specifikaciju Common Type
System (CTS) koju sve .NET komponente moraju potivati. Na primjer, u .NET-u je
sve objekt odreene klase koja izvodi iz korijenske klase System.Object. CTS podrava
opi koncept klasa, suelja i delegata (koji podravaju povratne pozive).
Uz to, .NET sadri i Common Language Specification koja prua niz osnovnih pravila
potrebnih za integraciju jezika. CLS postavlja minimalne zahtjeve koje jezik mora ispu-
njavati da bi bio.NET jezik. Prevoditelji koji su u skladu s CLS-om stvaraju objekte
koji mogu meusobno djelovati. Frameivork Class Library (FCL) moe u potpunosti
koristiti bilo koji jezik koji je u skladu s CLS-om.
.NET kostur se nalazi iznad operativnog sustava, a to moe biti bilo koja inaica Win-
dowsa i sastoji se od razliitih komponenata koje trenutno ukljuuju:
Pet slubenih jezika: C# , VB, Visual C++, Visual J# i JScript.N ET
CLR, objektno orijentiranu platformu za Windows i Web razvoj zajedniku svim
navedenim jezicima
Razliite povezane biblioteke klasa koje se zajedniki nazivaju Framework Class
Library
Na slici 1-1 prikazane su komponente .NET kostura.
Zbog arhitekture CLR-a, operacioni sustav moe biti bilo koja inaica operacionog sustava Unix ili neki
skroz drugi operacioni sustav.
4 | Programiranje C#
.NET kostur
Windows
Najvanija komponenta u .NET kosturu je CLR koja prua okruenje za izvoenje pro-
grama. CLR sadri virtualni stroj koji je u mnogo emu slian Java virtualnom stroju.
Na vioj razini CLR aktivira objekte, na njima izvodi sigurnosne provjere, pohranjuje ih
u memoriju, izvodi ih i odlae u otpad (Common Type System takoer je dio CLR-a).
Na slici 1-1 sloj iznad CLR-a je skup klasa kostura, iza kojeg slijedi dodatni sloj podat-
kovnih i X M L klasa, zatim jo jedan sloj klasa namijenjenih Web uslugama te Web
i Windows obrascima. Ove klase zajedniki ine FCL, jednu od najveih biblioteka
klasa u povijesti koja prua objektno orijentiran API za sve funkcionalnosti uahurene
u platformi .NET. Sa preko 4000 klasa, FCL omoguava brzi razvoj stolnih aplikacija,
klijent/posluitelj aplikacija te drugih Web usluga i apliakcija.
Skup osnovnih klasa, odnosno najnia razina FCL-a, slian je skupu klasa u jeziku
Java. Te klase podravaju ulaz i izlaz, rad s nizovima, upravljanje sustavom zatite,
mrenu komunikaciju, upravljanje dretvama, rad s tekstom, refleksiju, kolekcije itd.
Iznad te razine nalazi se sloj klasa koje proiruju osnovne klase tako da podravaju rad
s podacima i XML-om. Podatkovne klase podravaju rad s podacima koji se uvaju
u bazama podataka. Te klase ukljuuju Structured Query Language (SQL) klase koje
omoguavaju rad s podacima kroz standardno SQL suelje. .NET kostur podrava i
brojne druge klase koje omoguavaju rad s X M L podacima te njihovo pretraivanja i
prevoenje.
Kao proirenje osnovnih klasa kostura te podatkovnih i XML klasa, postoji i sloj klasa
koje su namijenjene izradi aplikacija s pomou tri razliite tehnologije: Web Services,
Web Forms i Windows Forms. Web Services ukljuuju velik broj klasa koje podra-
vaju razvoj jednostavnih distribuiranih komponenata koje e raditi ak i uz upotrebu
vatrozida i NAT posluitelja. Budui da Web Services kao temeljne komunikacijske
Prevoenje i MSI L
Na platformi .NET programi se ne prevode u izvedbene datoteke, oni se prevode u
sklopove koji sadre Microsoft Intermediate Language (MSIL) upute koje CLR zatim
pretvara u strojni kod i izvodi. MSIL (esto se koristi samo kratica IL) datoteke koje
proizvodi C# gotovo su identine IL datotekama koje proizvode ostali jezici podrani
u .NET platformi. Kljuna osobina CLR-a je da je on zajedniki: isti izvedbeni okoli
podrava razvoj na jezicima C# i VB.NET.
C# kod se prevodi u IL prilikom izrade projekta. IL se sprema u datoteku na disku.
Kada pokrenete program, IL se ponovno prevodi s prevoditeljem Just In Time (JIT).
Rezultat je strojni kod koji procesor moe izvesti.
Standardni se JIT prevoditelj pokree na zahtjev. Kada se metoda pozove, JIT prevodi-
telj analizira IL i proizvodi iznimno uinkovit strojni kod koji se vrlo brzo izvodi. Dok
se program izvodi prevoenje se provodi samo po potrebi, a jednom preveden kod se
sprema u privremenu memoriju da bi se mogao ponovno upotrijebiti. .NET aplikacije
sa svakim novim pokretanjem postaju sve bre jer se koristi ve prevedeni kod.
CLS znai da svi .NET jezici proizvode slian IL kod. To omoguava da se objektima
stvorenim u jednom jeziku moe pristupiti i iz drugog jezika. Stoga je mogue osnovnu
klasu stvoriti u jeziku VB.NET, a iz nje izvoditi u C# .
Jezik C#
Jezik C# je iznenaujue jednostavan. Sadri oko 80 kljunih rijei i desetak ugrae-
nih tipova, ali je vrlo izraajan kada je rije o implementaciji modernih programerskih
koncepata. C # prua svu podrku potrebnu za strukturirano, objektno orijentirano
programiranje temeljeno na komponentama kakvo biste i oekivali od modernog
jezika sagraenog na temeljima jezika C++ i Java. U inaici 2 .0 dodani su mu i mnogi
vani elementi koji su ranije nedostajali, poput generika i anonimnih metoda.
6 | Programiranje C#
Jezik C# razvio je mali tim koji predvode dva istaknuta Microsoftova inenjera,
Anders Hejlsberg i Scott Wiltamuth. Hejlsberg je poznat i kao autor jezika Turbo
Pascal koji je bio popularan na kunim raunalima te kao voa tima koji je razvio
Borland Delphi, jedan od prvih uspjenih integriranih razvojnih okolia za klijent/
posluitelj programiranje.
U sreditu svakog objektno orijentiranog jezika je njegova podrka za definiranje klasa
i rad s klasama. Klase definiraju nove tipove, to omoguava proirivanje jezika kako
biste bolje modelirali problem koji pokuavate rijeiti. C# sadri kljune rijei za dekla-
riranje novih klasa, njihovih metoda i svojstava te za implementaciju uahurivanja,
nasljeivanja i polimorfizma - tri stupa objektno orijentiranog programiranja.
U C# , sve to je potrebno za deklariranje klase nalazi se u samoj deklaraciji. Defini-
cije C# klasa ne zahtijevaju posebne datoteke zaglavlja niti IDL (Interface definition
Language) datoteke. tovie, C # podrava novi XML stil dokumentiranja koji pojed-
nostavljuje izradu dokumentacije.
C# podrava i suelja, koja su poput ugovora s klasom o pruanju usluga koje suelje
zahtijeva. U C# klasa moe nasljeivati samo iz jedne roditeljske klase, ali moe imple-
mentirati vie suelja. Kada implementira suelje, C# klasa ustvari obeava pruiti
funkcionalnosti koje suelje zahtijeva.
Prevoenjem koda zapravo stvarate sklop (engl. assembly). Sklop je kolekcija datoteka
koju programer vidi kao jednu dinamiki povezanu biblioteka (DLL) ili izvrnu dato-
teku (EXE). Na .NET platformi sklop je osnovna jedinica za ponovnu upotrebu, pra-
enje inaica, zatitu i razmjetaj.
8 | Programiranje C#
POGLAVLJE 2
9
Kao to je to sluaj u veini objektno orijentiranih programskih jezika, tip je u C#
definiran klasom, a pojedinane instance te klase nazivaju se objektima. U kasnijim
poglavljima objanjeno je da u jeziku C # postoje i drugi tipovi koji nisu klase, na
primjer enumeratori (engl. enums), strukture (engl. structs) i delegati (engl. delegates),
ali zasad emo se usredotoiti na klase.
Program Hello World deklarira jedan tip: klasu Hello. Ako u C # elite definirati
tip, deklarirate ga kao klasu koristei kljunu rije cla ss, date mu naziv - u ovom
sluaju ,,Hello - i zatim definirate njegova svojstva i ponaanja. Definicije svojstava i
ponaanja klase u C # moraju se nalaziti u vitiastim zagradama ({}).
Metode
Klasa ima svojstva i ponaanja. Ponaanja su definirana s metodama lanicama, a
svojstva su opisana u poglavlju 3.
Metoda )t funkcija u vlasnitvu klase. Zapravo, metode se ponekad i nazivaju funkcijama
lanicama. Metode lanice definiraju to klasa moe uiniti ili kako se ponaa. Meto-
dama se obino daju nazivi akcija koje izvode, na primjer WriteLine() ili AddNumbers().
Meutim, u ovdje navedenom primjeru metoda klase ima poseban naziv, Main(), koji ne
opisuje akciju, ali CLR-u govori kako je ovo glavna, odnosno prva metoda za klasu.
CLR prilikom pokretanja programa poziva Main(). Main() je ulazna toka programa i
svaki C# program je mora imati.'
Deklaracije metoda su zapravo ugovori izmeu autora i korisnika metode. Autor i
korisnik metode e vjerojatno biti isti programer, ali to ne mora uvijek biti sluaj. Moe
se dogoditi da jedan lan razvojnog tima napie metodu, a da je drugi koristi.
a*
Napomena za jav a programere: Main() je ulazna toka svakog C # pro-
grama, to je u odreenoj mjeri slino metodi run() u Java apletu ili
metodi Main() u Java programu.
Tehniki je u C# mogue imati nekoliko Main() metoda. U tom sluaju morate upotrijebiti preklopnik
/main u odzivniku da biste zadali klasu u kojoj se nalazi Main() metoda koja e sluiti kao ulazna toka za
program.
10 | Programiranje C#
Za deklariranje metode trebate zadati tip povratne vrijednosti i iza njega navesti ime.
U deklaracijama metoda obavezne su i zagrade, bez obzira na to prihvaa li metoda
parametre ili ne. Na primjer:
int myMethod(int sie)
deklarira metodu myMethod() koja ima jedan parametar - cjelobrojnu vrijednost koja
e se unutar metode koristit kao sie. Ova metoda vraa cjelobrojnu vrijednost. Tip
povratne vrijednosti korisniku metode govori koju e vrstu podataka metoda vratiti
kad zavri.
Neke metode uope ne vraaju vrijednosti. Za takve se metode kae da vraaju void,
to se posebno definira kljunom rijeju void. Na primjer:
void myVoidMethod();
deklarira metodu koja vraa void i nema parametara. U C# morate uvijek deklarirati
tip povratne vrijednosti ili void.
Komentari
C# program moe sadrati i komentare. Pogledajte prvi red iza otvorene vitiaste
zagrade ranije navedene glavne metode:
// Koristi objekt konzole sustava
Tekst poinje s dvije kose crte (//). One oznaavaju komentar. Komentar je napomena za
programera koja ne utjee na izvoenje programa. C# podrava tri vrste komentara.
Prva upravo prikazana vrsta govori da se sav tekst s desne strane oznake za komentar
treba smatrati komentarom, sve do zavretka tog reda. Ta se vrsta naziva komentarom
u C++ stilu.
Druga vrsta komentara naziva se komentar u C stilu i poinje otvorenom oznakom
za komentar (/*) a zavrava zatvorenom oznakom za komentar (*/). Na taj se nain
komentari mogu prostirati u vie redova i nije potrebno umetati znakove // na poetku
svakog reda, kao to je pokazano u primjeru 2-2.
Konzolne aplikacije
Hello W orld je primjer konzolne aplikacije (engl. console applicatiori). Konzolna
aplikacija obino nema grafikog korisnikog suelja - ne postoje izbornici, gumbi,
prozori i slino. Tekst se unosi i prikazuje u standardnoj konzoli (najee je to DOS
prozor pod Windowsima). Na poetku knjige bavit emo se samo konzolnim aplikaci-
jama kako bi se lake usredotoili na sam jezik. Kasnija poglavlja obrauju i Windows
i Web aplikacije te emo se tamo usredotoiti na alate za izradu grafikog korisnikog
suelja koje nudi Visual Studio .NET.
Metoda Main() iz naeg primjera jednostavno ispisuje tekst Hello W orld" na stan-
dardni izlaz (DOS prozor). Standardnim izlazom upravlja objekt Console. On ima
metodu WriteLine() koja uzima niz (skup znakova) i ispisuje ga na standardni izlaz.
Kada pokrenete ovaj program, u DOS prozoru na monitoru raunala pojavit e se
rijei Hello World.
Metoda se poziva operatorom toka (.). Stoga, kako biste pozvali metodu WriteLine()
objekta Console, napiite Console.W riteL ine(...) i u zagrade upiite niz koji elite
ispisati.
Imenski prostori
Console je samo jedan od brojnih tipova koji su dio .N ET FCL-a. Svaka klasa ima svoj
naziv, stoga FCL sadri na tisue naziva, kao to su ArrayList, Hashtable, FileDialog,
DataException, EventArgs itd. Postoje stotine, tisue, ak i desetine tisua naziva.
To predstavlja problem. Nijedan razvojni inenjer ne moe upamtiti sve nazive koji se
koriste na platformi .N ET te ete prije ili kasnije stvoriti objekt i dati mu naziv koji
se ve koristi. to e se dogoditi ako klasu Hashtable nabavite od drugog dobavljaa
i zatim otkrijete da je ona u sukobu s klasom Hashtable koju prua platforma .NET?
Upamtite, u C # svaka klasa mora imati jedinstven naziv a nazive gotovih klasa koje
ste kupili obino ne moete promijeniti.
Rjeenje ovog problema lei u upotrebi imenskih prostora. Imenski prostor (engl.
namespace) ograniava doseg naziva, ograniavajui njegovu smislenost samo na
definirani imenski prostor.*
12 | Programiranje C#
Recimo da je Jim inenjer. Rije inenjer11 moe znaiti mnogo toga i biti prilino
zbunjujua. Projektira li on zgrade? Pie programe? Izrauje vlakove?
Izraz moemo pojasniti tako da kaemo on je znanstvenik" ili on je strojarski
inenjer". C # programer moe objasniti kako je Jim Science.engineer, a ne train.
engineer. Imenski prostor (u ovom sluaju Science i train) ograniava doseg sljedee
rijei. On stvara prostor" unutar kojeg rije ima znaenje.
Nadalje, Jim moda nije bilo kakav science.engineer. Moda je Jim diplomirao na
sveuilitu M IT i ima titulu softverskog inenjera, a ne inenjera graevinarstva. To
znai da se objekt 3 im moe odreenije definirati kao Science. software.engineer. Ova
klasifikacija ukazuje kako je imenski prostor software smislen unutar imenskog pros-
tora science, a engineer je u ovom kontekstu smislen unutar imenskog prostora soft-
ware. Ako kasnije saznate kako je Charlotte transportation.train.engineer, odmah
e vam biti jasno kojoj ona vrsti inenjera pripada. Istovremeno mogu postojati dva
objekta engineer, svaki unutar svog imenskog prostora.
Slino tome, ako se ustanovi kako na platformi .NET postoji klasa Hashtafale unutar
imenskog prostora System.Collections, a vi ste unutar imenskog prostora Prog.Csharp.
DataStructures takoer stvorili klasu Hashtable, nee doi do sukoba jer svaka klasa
postoji unutar svog imenskog prostora.
Imenski prostori mogu pomoi u organizaciji i razvrstavanju tipova. Kada piete kom-
pleksni C # program, korisno je stvoriti vlastitu hijerarhiju imenskih prostora, koja
moe biti vrlo duboka. Svrha imenskih prostora je da vam pomognu da metodom
podijeli i vladaj" lake koristite sloenu hijerarhiju objekata.
Iako moete izjaviti da koristite imenski prostor System, za razliku od nekih drugih
jezika, ne moete izjaviti da koristite objekt System.Console. Primjer 2-4 se nee pre-
vesti.
Ako koristite Visual Studio, uvidjet ete da ste napravili pogreku, jer
kad unesete using System i iza toga stavite toku, Visual Studio .N ET
2005 e navesti popis valjanih imenskih prostora na kojem se ne nalazi
Console.
Koritenje kljune rijei using moe smanjiti koliinu koda koji trebate napisati, ali
moe i ponititi prednosti imenskih prostora jer zagauje doseg brojnim nazivima koji
14 | Programiranje C#
se preklapaju. Najee rjeenje je koritenje kljune rijei using uz ugraene imenske
prostore i one koje ste sami stvorili, ali ne i uz komponente koje ste nabavili od neke
tree strane.
Kako biste sprijeili ovakve pogreke na kojima se nepotrebno gube vrijeme i ener-
gija, trebate sastaviti pravilnik za imenovanje varijabli, metoda, konstanti itd. U ovoj
se knjizi varijable imenuju ,,deva zapisom (engl. camel notation) (npr. imeNekeVari-
jable), a metode, konstante i svojstva Pascalovim zapisom (npr. NekaMetoda).
Kljuna rije static govori kako Main() moete pozvati bez prethodnog stvaranja
objekta tipa Hello. Ova pomalo kompleksna tema bit e detaljnije obraena u kasnijim
poglavljima. Jedan od problema koji se javljaju prilikom uenja novog programskog
jezika je potreba za koritenjem sloenijih znaajki prije njihova potpuna razumi-
jevanja. Za sada deklaraciju metode Main() moete smatrati arobnom formulom.
* r $ffHeBoWoHd| .7. ..
J u f* 2 U C :\^cu m e rtsa n S e ttin g s \A m in is tra to r\M y Docum ents\Visual S tudo\P rojecl
S o W lo n N e S lH e lk M o H d P , 0 to B f to ry fo r S o U io n i
----- vi'*- v sfV i
m
iSr
Slika 2-1. Izrada C # konzolne aplikacije u Visual Studiju .NET
16 J Programiranje C#
Za otvaranje aplikacije odaberite Visual C# u prozoru Project Types, a u prozoru
Templates Console Application (ovaj korak ne morate izvesti ako koristite Visual C#
Express Edition - izravno odaberite Console Application).
Sada moete upisati naziv projekta i odabrati mapu u koji ete spremati datoteke. Pritis-
nite OK i otvorit e se novi prozor u koji moete upisati kod iz primjera 2-1 (slika 2-2).
m
! h u s in g S y s tem ;
u s in g 3 y s t e i T i . C o l l e c c io n s . 0 e n e r i
I*] - fc jj P roperties
fi- g j References
[ - u s in g S y s te r o .T e x t ;
- tfe n d re g io n
^ SoU ion Explorer | l ^ ,'Cl&jV'9W |~
^ B n am esp ac e H e U o tJo rld
t a c i : v o id H a i n ( s t r i n g [ ] a rg s)
{ B ,Advanced' Compie
^BuMAction
:}Copyto Output IFalse
Custom Tod
D>* Custom Tod Nan
&fflSjCv-> c
t-bFile Mame Program.es
$ Full Path ' C:\Docijmonts and 5
s
s gpeisw lW KM f
r *-<>.\ _________ .*> & ?. "A i
Primijetit ete kako Visual Studio .NET imenski prostor stvara prema navedenom
nazivu projekta (HelloWorld) i dodaje direktivu using za System, System.Collections.
Generic i System.Text jer e tipovi iz tih imenskih prostora biti potrebni za gotovo svaki
program koji budete pisali.
Visual Studio .NET stvara klasu Program koju slobodno moete preimenovati. Kada
klasi mijenjate naziv, dobro je promijeniti i naziv datoteke (Classl.cs). Ako promijen-
ite naziv datoteke, Visual Studio e automatski umjesto vas promijeniti naziv klase.
Za reprodukciju primjera 2-1 promijenite ime datoteke Program.es (nalazi se u pro-
zoru Solution Explorer) u hello.es te promijenite ime Program u HelloWorld (ako imena
promijenite obrnutim redoslijedom, Visual Studio e promijeniti ime klase u hello).
Na kraju, Visual Studio 2005 stvara kostur programa kako biste lake zapoeli s
radom. Za reprodukciju primjera 2-1 uklonite argumente (string[ ] args) iz metode
Main(). Zatim sljedea dva reda kopirajte u tijelo metode Main():
Ako ne koristite Visual Studio .NET, otvorite Notepad, unesite kod iz primjera 2-1 i
datoteku spremite kao tekstualnu datoteku hello.es.
18 | Programiranje C#
Pravovrem eno prevoenje
Prevoenjem program a hello.es koristei esc stvara se izvedbena datoteka. Upamtite
da su u .exe datoteci instrukcije zapisane u M SIL-u, koji je opisan u poglavlju 1.
Zanim ljivo je da, ako ovu aplikaciju napiete u V B.N ET -u ili bilo kojem drugom
jeziku sukladnom s .N E T C L S-om , dobit ete vie-m anje isti MS1L. Razlike izmeu
IL ko d a stvorenog u razliitim jezicim a praktiki ne postoje.
Uz to to stvara IL kod, prevoditelj stvara i segm nt ,exe datoteke sam o za itanje u
koji um ee standardno W in 3 2 izvedbeno zaglavlje. Prevoditelj zadaje ulaznu toku
unutar segm enta sam o za ita nje. Program za uitavanje prelazi na tu toku kada
pokrenete program , ba kao i kod svakog drugog programa za W indowse.
O peracioni sustav, m eutim , ne moe izvesti IL kod i ta ulazna toka slui samo za
prijelaz do .N ET J1 T prevoditelja (koji je takoer opisan u poglavlju 1). J1 T prevoditelj
generira originalne instrukcije za procesor kakve se mogu pronai u obinim ,exe
datotekam a. K ljuno svojstvo J1 T prevoditelja zapravo je da se metode prevode samo
prilikom koritenja, kad su na redu za izvoenje.
Ovim korakom pravi se EXE datoteka. Ako program sadri pogreke, prevoditelj
e o njima izvijestiti u prozoru odzivnika. Preklopnik /debug u kod umee sim-
bole tako da EXE datoteku moete pokrenuti pod programom za ispravljanje
pogreaka ili pogledati brojeve redova koda u tragovima stoga (trag stoga ete
dobiti ako program generira pogreku koju ne obraujete).
4. Za pokretanje programa pod .NET-om unesite:
hello
1
1 for ( int i = 0; i < 3; i++ )
{
)
>
)
Za pokretanje alata za ispravljanje pogreaka moete odabrati Debug -> Start ili jed-
nostavno pritisnuti F5. Program se zatim prevodi i izvodi do toke prekida, na njoj se
zaustavlja, a uta strelica oznaava sljedei iskaz za izvoenje, kao to je prikazano
na slici 2-6.
0 (winArray[i] .Dra*rtJindow();
}
}
)
20 | Programiranje C#
Nakon to ste doli do toke prekida, provjera vrijednosti razliitih objekata je
jednostavna. Na primjer, vrijednost varijable i vidjet ete ako iznad nje postavite
pokaziva mia i priekate nekoliko trenutaka (slika 2-7).
U IDE alatu za ispravljanje pogreaka postoji i niz korisnih prozora, kao to je prozor
Locals u kojem su prikazane vrijednosti svih lokalnih varijabli (slika 2-8).
> c o u n te r 0 in t
Gfl w in {V irtu a lM e th o d s.W in d o w } VirtualM ethods.VVindow
B lb {V irtu a lM etho ds.LlstB o x) V irtu a lM e th o d s.listB o x
b {V irtu a lM e th o d s.B u tto n ) V irtua lM ethod s.B utton
fJ * w inArray {Dimensions:[33^ VirtualMethods.Vtfnovvl]
] A u to s j L o c a ls J | p W a tch 1
Ugraeni tipovi, poput cjelobrojnih vrijednosti, prikazuju vrijednost, ali objekti prika-
zuju sv,oj tip i uz njih je prikazan znak plus (+). Te objekte moete proiriti kako biste
vidjeli njihove unutarnje podatke (slika 2-9). Vie o objektima i njihovim unutarnjim
podacima moete saznati u poglavljima koja slijede.
a {V irtu alM etho ds.B utto n). V irtua lM ethod s.B utton
a ^ w ln A rra y {D im e n sio n s:{3 )) V irtudlM ethods.W indo(v{)
M S 0 [0 ] {V irtu a lM e th o d s.W in d o w ) V irtua lM ethod s,W ind ow
22 | Programiranje C#
POGLAVLJE 3
Tipovi
C # je vrlo tipiziran jezik. U takvom jeziku morate deklarirati tip (engl. type) svakog
objekta kojeg stvorite (npr. cjelobrojnih vrijednosti, brojeva s pominim zarezom,
nizova, prozora, gumba itd.), a prevoditelj e sprijeiti pojavu pogreaka tako to e
inzistirati da objektima budu pridrueni samo podaci odgovarajueg tipa. Tip objekta
govori prevoditelju koliko je objekt velik (npr. int oznaava objekt od 4 bajta) i koje su
njegove mogunosti (npr. gumbi se mogu povui, pritisnuti i tako dalje).
23
Napomena za C # 1.1 programere: sve do inaice 2 platforma .N ET bila
je vrlo tipizirana u svemu osim u kolekcijama. Uvoenjem generika
i*, stvaranje vrlo tipiziranih klasa kolekcija sada je jednostavno, kao to
je prikazano u poglavlju 9.
Poput jezika C++ i Java, C # tipove dijeli u dva skupa: ugraene (engl. intrinsic ) tipove
koji su dio samog jezika i koris n i ki d efin ira n e tipove koje definira programer.
C # skup tipova dijeli na jo dvije kategorije: v rijed n osn e i referen tne tipove.' Osnovna
razlika izmeu vrijednosnih i referentnih tipova je nain spremanja njihovih vrijedno-
sti u memoriju. Vrijednosni tip uva svoju vrijednost u memoriji dodijeljenoj na stogu
(engl. stack).
Ako imate vrlo velik objekt, njegovo smjetanje na gomilu ima mnogo prednosti. U
poglavlju 4 objanjene su prednosti i nedostaci rada s referentnim tipovima. Ovo se
poglavlje bavi ugraenim vrijednosnim tipovima koji su dostupni u C# .
C # podrava tipove p o k a z iv a a u C++ stilu, ali oni se koriste samo kod rada s neu-
pravljanim kodom. To je kod koji nije stvoren na platformi .NET, na primjer, COM
objekti. (Rad s COM objektima objanjen je u poglavlju 22.)
Svi ugraeni tipovi, osim Object (koji je detaljnije opisan u poglavlju 5) i String (opisan u poglavlju 10) su
vrijednosni tipovi. Svi korisniki definirani tipovi, osim struktura (pogledajte poglavlje 7) i enumeriranih
tipova (pogledajte poglavlje 3) su referentni tipovi.
24 | Programiranje C#
Napomena za Java programere: C # ima iri raspon osnovnih tipova
od jezika Java. Treba istaknuti decimalni tip u C # koji je koristan za
financijske izraune.
Svaki tip ima odreenu i nepromjenjivu veliinu. Za razliku od C++, veliina int tipa u
C# je uvijek 4 bajta jer se on preslikava u Int32 u .NET CLS-u. U tablici 3-1 popisani
su ugraeni vrijednosni tipovi dostupni u jeziku C# .
Veliina (u
Tip bajtovima) .NETtip Opis
Uz ove primitivne tipove C # ima jo dva vrijednosna tipa: enum (objanjen kasnije u
ovom poglavlju) i struct (objanjen u poglavlju 4). U poglavlju 4 objanjene su i druge
pojedinosti vrijednosnih tipova, poput primjene vrijednosnih tipova kao referentnih
tipova u postupku koji je poznat pod nazivom pakiranje (engl. boxing) i injenice da
vrijednosni tipovi ne nasljeuju.
rt *
Napomena za C i C++ programere: C # upravlja svom memorijom s
pomou sustava za sakupljanje otpada - ne postoji operator za brisanje.
Float, double i decimal nude razliite stupnjeve veliine i preciznosti. Float je dobar za
veinu malih necjelobrojnih vrijednosti. Uzmite u obzir da prevoditelj pretpostavlja
da je svaki broj s decimalnim zarezom double ako ne kaete drukije. Za doslovnu
dodjelu tipa float iza broja dodajte slovo f (pojedinosti pridruivanja vrijednosti litera-
lima objanjene su kasnije u ovom poglavlju):
float someFloat = 57f;
26 | Programiranje C#
Tip char p redstavlja U nicode z n ak . ch ar sp e cija ln i sim b o li m ogu biti jed n o sta v n i zn a -
kovi, U n ico d e ili kon trolni z n a ko v i (engl. e s cap e ch aracters ) sm je ten i izm eu a p o -
strofa. N a p rim jer, Aje je d n o sta v a n z n a k , dok je \u004l U nicode znak. K o n tro ln i zn a -
kovi su p o se b n i to ken i ko ji se sa s to je od dva z n a k a , od k o jih je prvi ob rn u ta kosa
crta . N a p rim jer, \t je vodoravni tabu lator. U o b iaje n i k o n tro ln i znakovi navedeni su
u ta blici 3 - 2 .
Znak Znaenje
V Apostrof
\" Navodnik
\a Upozorenje
\b Brisanjeunatrag
\f Nova stranica
\n Novi red
\t Vodoravni tabulator
\v Okomiti tabulator
Ako provedete obrnutu pretvorbu, moe lako doi do gubitka informacija. Ako je vri-
jednost u in t vea od 32 767 njen dio se moe izgubiti prilikom pretvorbe. Prevoditelj
nee izvesti implicitnu pretvorbu iz in t u short:
short x;
int y = 5 0 0 ;
x = y; // Nee se prevesti
Svi ugraeni tipovi sami definiraju vlastita pravila pretvorbe. Ponekad je zgodno defini-
rati pravila pretvorbe za korisniki definirane tipove, a to je objanjeno u poglavlju 5.
Varijable i konstante
Varijabla (engl. variable ) je lokacija u memoriji s tipom. U prethodnim su primjerima
i x i y varijable. Varijablama se mogu pridruiti vrijednosti koji se mogu programski
promijeniti.
WriteLine()
.N E T kostu r sadri korisnu metodu za ispis na zaslon. Pojedinosti m etode System.
C onsole.W riteLine() bit e pojanjene kasnije u knjizi, ali osnove su jednostavne. Pozo-
vite m etodu kako je prikazano u prim jeru 3 -1 , unosei niz koji elite ispisati na kon-
zoli i param etre koji e se zam ijeniti. U sljedeem prim jeru:
niz A fter assignment, mylnt se ispisuje kao takav, iza ega slijedi v rijednost varija-
ble mylnt. Lokacija param etra zam jene { 0 } zadaje gdje e se prikazati vrijednost prve
izlazne varijable mylnt - u ovom sluaju, na kraju niza. U sljedeim poglavljim a saznat
ete m nogo vie o WriteLine().
Varijablu moete napraviti tako to ete deklarirati njezin tip i zatim joj dodijelite naziv.
Moete ju inicijalizirati prilikom deklariranja, a novu vrijednost jo j moete dodijeliti
bilo kada, jednostavnom promjenom vrijednosti. To je prikazano u primjeru 3-1.
28 | Programiranje C#
primjer 3-1- Inicijalizacija varijable i pridruivanje vrijednosti varijabli
(tregion Using directives
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace InitializingVariables
{
class Values
{
static void Main()
{
int mylnt = 7;
Sytem.Console.WriteUne(Initialized, mylnt: {o}",
mylnt);
mylnt = 5;
System.Console.WriteLine("A-fter assignment, mylnt: { o }\
mylnt);
}
}
}
Obavezno pridruivanje
U jeziku C # pridruivanje je obavezno: to jest, varijable se moraju inicijalizirati ili im
se mora pridruiti vrijednost prije koritenja. Kako biste isprobali ovo pravilo, promi-
jenite red koji inicijalizira mylnt u primjeru 3-1 u:
int mylnt;
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace UninitializedVariable
{
class UninitializedVariable
{
static void Main(string[] args)
{
int mylnt;
System.Console.WriteLine
("Uninitialized, mylnt: {0}", mylnt);
mylnt = 5;
System.Console.WriteLine("Assigned, mylnt: {0}", mylnt);
}
}
}
Kada pokuate prevesti ovaj ispis, C # prevoditelj e prikazati poruku o pogreci pri-
kazanu na slici 3-1.
J D escrlpUon . __ ^ ; | . . F fe . . - i C olum n I
1 U se o f u nassigned local v a riab le 'm y ln t' U n in itia lized V ariable.es 17 33
Slika 3-1. Poruka o pogreci nastaloj zbog koritenja varijable kojoj nije dodijeljena vrijednost
Ako dvaput pritisnete poruku o pogreci razvojni okoli e postaviti kursor na mjestu
pogreke u kodu.
U C# nije doputeno koritenje varijabli koje nisu inicijalizirane. Znai li to da svaku
varijablu u programu morate inicijalizirati? Zapravo, ne. Ne morate stvarno inicija-
lizirati varijablu, ali joj prije koritenja morate dodijeliti vrijednost. U primjeru 3-3
prikazana je ispravna inaica programa.
30 | Programiranje C#
Primjer 3-3. Pridruivanje bez inicijaliziranja
#region Using directives
using System;
using System.Colle ctio ns.G eneric;
using System.Text;
#endregion
}
}
}
Konstante
K onstanta (engl. constan t ) je varijabla ija se vrijednost ne moe promijeniti. Varijable
predstavljaju moan alat, ali ponekad je potrebna tono odreena vrijednost, vrijed-
nost za koju elite biti sigurni da e ostati nepromijenjena. Na primjer, u programu za
simuliranje kemijskog eksperimenta trebate koristiti toke vrelita i ledita na Fahren-
heitovoj skali. Program e biti jasniji ako varijable u koje se vrijednosti spremaju nazo-
vete FreezingPoint i BoilingPoint, ali ne elite dopustiti da se njihove vrijednosti pro-
mijene. Kako to sprijeiti? Rjeenje je koritenje konstanti.
Postoje tri vrste konstanti: literali (engl. literals ), sim bolike k on stan te i enu m eracije
(engl. en um erations). U izrazu:
x = 32;
vrijednost 32 je literal. 32 uvijek ima vrijednost 32. Toj konstanti ne moete dodijeliti
drugu vrijednost. Koliko god se trudili ne moete postii da 32 predstavlja vrijednost 99.
Simbolike konstante pridruuju naziv konstantnoj vrijednosti. Simbolilytkonstantu
moete deklarirati s pomou kljune rijei const i sljedee sintakse;/
const tip identifikator=vrijednost;
using System;
using System.Collections.Generic;
using System.Text;
(tendregion
namespace SymbolicConstants
{
class SymbolicConstants
{
static void Main(string[] args)
{
const int FreezingPoint = 32; // Stupnjevi Fahrenheita
const int BoilingPoint = 212;
BoilingPoint = 2 1 ;
}
}
)
U primjeru 3-4 stvorene su dvije simbolike cjelobrojne konstante; FreezingPoint i Boi-
lingPoint. Nazivi konstanti napisani su Pascalovim stilom, no to nije obavezno.
Svrha ovih konstanti je da u svim potrebnim izrazima koriste vrijednosti 32 i 212 za
toke ledita i vrelita ali, budui da konstante imaju nazive, one prenose mnogo vie
znaenja. Ako odluite program prebaciti na Celzijusovu skalu, konstante moete
ponovno inicijalizirati prilikom prevoenja na 0 i 100. Ostatak koda trebao bi nor-
malno funkcionirati.
Kako biste se uvjerili da se konstanti ne moe ponovno dodijeliti vrijednost, pokuajte
ukloniti oznaku komentar iz posljednjeg reda u kodu (prikazan podebljanim slovima).
Prilikom ponovnog prevoenja trebala bi se javiti pogreka prikazana na slici 3-2.
Slika 3-2. Upozorenje koje se pojavljuje kada konstanti pokuate ponovno dodijeliti vrijednost
32 | Programiranje C#
Enumeracije
Enumeracije (engl. enumerations) su iznimno korisna alternativa konstantama. Enu-
meracija je samostojan vrijednosni tip koji se sastoji od skupa imenovanih konstanti
(naziva se i enumeratorski popis).
U primjeru 3 -4 stvorili ste dvije povezane konstante:
const int FreezingPoint = 32;
const int BoilingPoint = 212;
Iza svake enumeracije nalazi se temeljni tip koji moe biti bilo koji tip cjelobrojne vri-
jednosti (integer, short, long itd.) osim char. Tehnika definicija enumeracije je:
[atributi] [modifikatori] enum identifikator
[:osnovni tip] {enumeratorski popis};
Osnovni tip je temeljni tip enumeracije. Ako izostavite ovu neobaveznu vrijednost (to
se esto dogaa), ona e poprimiti vrijednost int, ali slobodno moete koristiti bilo
koji tip cjelobrojne vrijednosti (npr. ushort, long) osim char. Sljedei odlomak, na pri-
mjer, deklarira enumeraciju cjelobrojnih vrijednosti bez predznaka (uint):
enum ServingSizes :uint
{
Small = 1 ,
Regular = 2,
Large = 3
}
Obratite panju na enumeratorski popis kojim zavrava deklaracija. On sadri pridru-
ene konstante za enumeraciju koje su odvojene zarezima.
using System;
using System.Collections.Generic;
using System.Text;
ttendregion
namespace EnumeratedConstants
{
class EnumeratedConstants
{
enum Temperatures
{
WickedCold = 0,
FreezingPoint = 32,
Light3acketWeather = 60,
SwimmingWeather = 72,
BoilingPoint = 212,
}
static void Main(string[] arg)
{
System.Console.WriteLine("Freezing point of water: {0}",
(int)Temperatures.FreezingPoint);
System.Console.WriteLine("Boiling point of water: {0},
(int)Temperatures.BoilingPoint);
}
}
}
Kao to moete primijetiti, enum se mora kvalificirati tipom enumeracije (npr. Tempera-
tures. WickedCold). Vrijednost enumeracije se podrazumijevano prikazuje s pomou
simbolikog naziva (kao to su BoilingPoint i FreezingPoint). Kada elite prikazati
vrijednost enumerirane konstante, konstantu morate pretvoriti u njen temeljni tip
(int). Cjelobrojna vrijednost se prosljeuje u WriteLine i prikazuje.
34 | Programiranje C#
v rijedn ost First b it e o, Second e im ati vrijedn o st l, Third 20, a Fourth 21.
E n u m eracije su fo rm a ln i tip ovi stoga je za pretvorbu tipa en u m era cije u tip cje lo b ro jn e
vrijedn o sti p o tre b n a e k sp licitn a pretvorba.
Nizovi znakova
Gotovo je nemogue napisati program u jeziku C # bez upotrebe nizova. U objektu
niza nalazi se niz znakova.
Varijabla niza se deklarira kljunom rijei string, isto kao kod stvaranja instance bilo
kojeg objekta:
string myString;
Identifikatori
Identifikatori (engl. identifiers) su nazivi koje programeri odaberu za svoje tipove,
metode, varijable, konstante, objekte itd. Identifikator mora poinjati slovom ili
donjom crtom.
Standardna Microsoft praksa imenovanja predlae ,,deva zapis (malo poetno slovo,
npr. nekolme) za nazive varijabli i Pascalov zapis (veliko poetno slovo, npr. NekoDrugo-
Ime) za nazive metoda i veinu drugih identifikatora.
Izrazi
Iskazi koji su jednaki nekoj vrijednosti zovu se izrazi (engl. expressions). Iznenaujue
velik broj iskaza je jednak nekoj vrijednosti. Na primjer, pridruivanje:
Bijeli prostor
U jeziku C # se razmaci, fabulatori i novi redovi smatraju bijelim prostorom" (engl.
whitespace ) (nazvani tako jer se vidi samo bjelina stranice na kojoj je napisan kod).
Dodatni bijeli prostor u C # iskazima se uglavnom zanemaruje. Moete napisati:
myVariable = 5;
ili:
myVariable = 5;
Iznimka ovog pravila je bijeli prostor unutar nizova koje se ne zanemaruju. Ako
napiete:
Console.WriteLine("Hello World")
svaki razmak izmeu Hello" i ,,World bit e tretiran kao znak u nizu.
Koritenje bijelog prostora uglavnom je intuitivno. Treba ga koristiti tako da kod bude
to itljiviji programeru, a prevoditelju to ionako nije bitno.
Postoje situacije u kojima je upotreba bijelog prostora vrlo bitna. Iako je izraz:
int x = 5;
isti kao:
int x=5;
36 | Programiranje C#
rostor izmeu deklaracije tipa in t i naziva varijable x nije suvian, ve je obavezan.
To nije iznenaujue: bijeli prostor prevoditelju omoguuje razlikovanje kljune rijei
in t i nekog nepoznatog termina in tx . Izmeu i n t i x moete dodati koliko god elite
bjelina, ali mora postojati najmanje jedna (obino razmak ili tabulator).
Iskazi
Potpuna programska uputa u C# naziva se is ka zo m (engl. statem en t). Programi se
sastoje od nizova C# iskaza. Svaki iskaz mora zavravati tokom zarez (;). Na pri-
mjer:
int x; // iskaz
x = 23; // jo jedan iskaz
int y = x; // i jo jedan iskaz
Na tijek programa utjeu i petlje i iteracijski iskazi koji se oznaavaju kljunim rijeima
for, while, do, in i foreach. Iteracija je objanjena kasnije u ovom poglavlju. Prvo emo
objasniti neke osnovnije metode uvjetnog i bezuvjetnog grananja.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace CallingAMethod
{
class CallingAMethod
1
Iskazi if...else
Iskazi i f . . .e lse oznaavaju grananje temeljeno na uvjetu. Uvjet je izraz koji se testira
na poetku iskaza i f . Ako je uvjet istinit, izvodi se iskaz (ili blok iskaza) u glavnom
dijelu i f iskaza.
i f iskazi mogu sadrati dodatni iskaz else. On se izvodi samo ako je izraz na poetku
iskaza i f neistinit:
if (izraz)
iskazi
[else
iskaz2]
38 | Programiranje C#
M oete p rim ije titi i da je isk az e l s e n e obav ezan, bu dui da se n alazi u n u tar u glatih
zagrada. Ia k o je tim e o b ja n je n a sin ta ksa iska za i f , u p otreba e b iti ja sn ija pogledate
li p rim jer 3-7.
Testiranje je li valueOne vee od valueTwo daje neistinit rezultat (jer je valueOne jednako
10, a valueTwo je jednako 2 0 ,stoga valueOne nije vee od valueTwo). Poziva se iskaz else
koji ispisuje iskaz:
Drugi je iskaz i f istinit i svi iskazi u bloku i f se procjenjuju, to uzrokuje ispis sljedea
dva reda:
Setting valueTwo to valueOne value,
and incrementing ValueOne.
ValueOne: 31 ValueTwo: 30
Blokovi iskaza
Blok iskaza moe se napisati na svakom m jestu na kojem C # oeku je iskaz. Blok
iskaza je skup iskaza sm jeten u vitiaste zagrade.
Stoga um jesto:
if (nekillvjet)
nekilskaz;
m oete napisati:
if(nekillvjet)
{
iskazledan;
iskazDva;
iskazTri;
}
Ugnijeeni iskazi if
Iskazi i f se esto ugnjeuju kako bi se upravljalo sloenim uvjetima. Pretpostavimo
da trebate napisati program za provjeru temperature koji vraa sljedee informacije:
Ako je temperatura 32F ili nia, program bi vas trebao upozoriti o ledu na
cestama.
Ako temperatura iznosi tono 32F, program bi vam trebao rei kako moe doi
do zaleivanja.
Postoji mnogo dobrih naina za pisanje ovakvog programa. U primjeru 3 -8 pokazan
je pristup u kojem se koriste ugnijeeni iskazi i f .
using System;
using System.Collections.Generic;
using System.Text;
#endregion
40 l Programiranje C#
Primjer 3-8. Ugnijeeni iskazi if (nastavak)
namespace Nestedlf
class Nestedlf
{
static void Main()
{
int temp = 3 2 ;
if ( temp <= 32 )
{
Console.WriteLine( "Narning! Ice on road!" );
if ( temp == 32 )
{
Console.WriteLine(
"Temp exactly freezing, beware of water." );
}
else
{
Console.WriteLine( "Watch for black ice! Temp: {0 }", temp );
} // zavrava else
} // zavrava if (temp <= 3 2 )
} // zavrava main
} U zavrava class
} // zavrava namespace
U jezicim a C i C + + ovakav iskaz moe biti opasan. Neiskusni programeri esto umje-
sto.operatora jedn akosti koriste operator pridruivanja te tako napisu iskaz:
if (temp = 3 2 )
Program zatim provjerava je li temperatura jednaka 32F. Ako je, ispisuje se jedna
poruka; ako nije, temperatura mora biti manja od 32F i program ispisuje drugu
poruku. Primijetite da je drugi iskaz i f , ugnijeen unutar prvog i f , tako da je logika
iza else budui da je ustanovljeno kako je temperatura manja ili jednaka 32F i pri-
tom nije jednaka 32F, onda mora biti manja od 32F.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace SwitchStatement
{
class SwitchStatement
{
42 | Programiranje C#
Primjer 3-9. Iskaz switch (nastavak)
static void Main( string[] args )
switch ( myChoice )
{
case Democrat:
Console.WriteLine( "Vou voted Democratic.Nn" );
break;
case LiberalRepublican: // propada kroz
//Console.WriteLine(
//"Liberal Republicans vote Republican\n");
case Republican:
Console.WriteLine( "Vou voted Republican.\n" );
break;
case NewLeft:
Console.WriteLine( "NewLeft is now Progressive" );
goto case Progressive;
case Progressive:
Console.WriteLine( "Vou voted Progressive.\n" );
break;
case Libertarian:
Console.WriteLine( "Libertarians are voting Republican" );
goto case Republican;
default:
Console.WriteLine( "You did not pick a valid choice.Nn" );
break;
}
Console.WriteLine( "Thank you for voting." );
}
}
}
U ovom primjeru pravimo konstante za razliite politike stranke. Varijabli myChoice
pridruuje se jedna vrijednost (Libertarian) i program se prebacuje na tu vrijednost.
Ako je myChoice jednaka vrijednosti Democrat, ispisuje se iskaz. Primijetit ete da ovaj
sluaj zavrava s break. break je iskaz za preskakanje kojim se iz iskaza switch preba-
cujemo na prvi sljedei red koji ispisuje Thank you for voting".
Ako vam je potreban iskaz, ali iza toga elite izvesti drugi sluaj, moete koristiti iskaz
goto, kao to je prikazano u sluaju NewLeft:
goto case Progressive;
Iskaz goto vas ne mora prebaciti na prvi sljedei sluaj. U sljedeoj instanci izbor
Libertarian takoer sadri goto, ali njime se ovaj put prebacuje nazad sve do sluaja
Republican. Budui d aje naa vrijednost postavljena na Libertarian, dogaa se upravo
ovo. Ispie e iskaz Libertarian, dolazi do prebacivanja na sluaj Republican, ispisuje
se taj iskaz, zatim se dolazi do break, to nas prebacuje izvan switch sve do posljednjeg
iskaza. Izlaz svega ovog je:
Libertarians are voting Republican
You voted Republican.
44 | Programiranje C#
Obratite panju na uvjet default iz primjera 3-9:
default:
Console.WriteLine(
"You did not pick a valid choice.Nn");
Iteracijski iskazi
C# nudi irok raspon iteracijskih iskaza, ukljuujui petlje for, while i do..,while te
petlje foreach (nove u C jezicima, no ve poznate VB programerima). Uz to, C# podr-
ava iskaze za preskakanje goto, break, continue i return.
Iskaz goto
Iskaz goto je izvor iz kojeg potjeu svi ostali iteracijski iskazi. Na alost, radi se o
sjemenu iz kojeg je potekao pageti kod i beskonana zbunjenost. Najiskusniji pro-
grameri vjerojatno se jee od iskaza goto, ali kako ne biste ostali neinformirani, evo
kako se on koristi:
1. Stvorite oznaku.
2. Odete na tu oznaku.
Oznaka je identifikator iza kojeg slijedi dvotoka. Naredba goto obino se povezuje s
uvjetom, kao to je prikazano u primjeru 3-10.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace UsingGoTo
{
class UsingGoTo
{
static void Main( string[] args )
{
int i = 0;
repeat: // Oznaka
Console.WriteLine( "i: {0}", i );
i++;
if ( i < 10 )
goto repeat; // Zlodjelo
return;
}
}
}
Kad biste pokuali nacrtati tijek kontrole u programu u kojem se esto koriste iskazi
goto, rezultat, brojne ukriene i preklopljene linije, vjerojatno bi vas podsjetio na tanjur
pun pageta. Otuda i potjee naziv pageti kod. Taj je fenomen doveo do nastanka
alternativnih rjeenja, poput petlje while. Mnogi programeri dre da se goto treba
koristiti samo u najjednostavnijim problemima, u suprotnom je nastali kod iznimno
zbunjujui i teak za odravanje.
Petlja vvhile
Semantika petlje while je dok je ovaj uvjet istinit, obavljaj taj posao11. Sintaksa je:
while (izraz) iskaz
Izraz je, kao i inae, bilo koji iskaz koji vraa vrijednost. Iskazi wbile zahtijevaju izraz
koji odgovara Boolean vrijednosti (true/false), a takav iskaz moe naravno biti i blok
iskaza. Primjer 3-11 aurira primjer 3-10 upotrebom petlje while.
using System;
using System.Collections.Generic;
using System.Text;
itendregion
namespace WhileLoop
{
class WhileLoop
{
static void Main( stringf] args )
{
int i = 0;
while ( i < 1 0 )
{
Console.WiiteLine( "i: {o}", i );
i++;
}
46 | Programiranje C#
P r im je r 3 -1 1 - U p o t r e b a p e t l j e w h ile ( n a s ta v a k )
return;
}
}
}
Kod iz primjera 3-11 daje identine rezultate kao kod iz primjera 3-10, ali je njegova
logika neto jasnija. Iskaz while je jednostavan i kompletan, a ima znaenje dok je i
manje od 10, ispisuj ovu poruku i poveavaj i .
Primijetit ete da petlja while testira vrijednost i prije ulaska u petlju. Time se osigu-
rava da se petlja nee pokrenuti ako je testirani uvjet netoan. Stoga, ako se i inicijali-
zira s U , petlja se uope nee pokrenuti.
Petlja do...while
Iskaz while se moda uope nee izvesti ako testirani uvjet bude neistinit. Ako elite
osigurati da se iskaz izvede barem jednom, koristite petlju do.. .while:
do iskaz while izraz
Izraz je bilo koji iskaz koji vraa vrijednost. U primjeru 3-12 prikazana je petlja do...
while.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace DoWhile
{ '
class Doklhile
{
static void Main( stringj] args )
{
int i = 1 1 ;
do
{
Console.WriteLine( "i: {o}", i );
i++;
} while ( i < 10 );
return 0 ;
}
}
}
Ovdje se i inicijalizira s 11 i test while nee uspjeti, ali tek nakon to se tijelo petlje
jednom izvede.
using Sysi:em;
using System.Collections.Generic;
using System.Text;
#endregion
namespace ForLoop
{
class ForLoop
{
static void Main( string[] args )
{
for ( int i = 0; i < 1 0 0 ; i++ )
{
Console,Write( "{0 } ", i );
if ( i % 10 == 0 )
{
Console.WriteLine( "Yt{0}", i );
} '
}
return ;
}
}
}
Izlaz:
0 0
i ;! 3 4 5 6 7 8 9 10 10
n 12 13 14 15 16 17 18 19 20 20
21 22 23 24 25 26 27 28 29 30 30
31 32 33 34 35 36 37 38 39 40 40
41 42 43 44 45 46 47 48 49 50 50
51 52 53 54 55 56 57 58 59 60 60
61 62 63 64 65 66 67 68 69 70 70
71 72 73 74 75 76 77 78 79 80 80
81 82 83 84 85 86 87 88 89 90 90
91 92 93 94 95 96 97 98 99
48 | Programiranje C#
Ova petlja k oristi op era to r m odulo (engl. m odulus) koji je opisan kasn ije u ovom pogla-
vlju V rijedn ost i se isp isu je sve d o k i n ije v ie k ra tn ik od 10.
i f ( i % 10 == o)
Z atim se ispisuje tabulator, a iza njega vrijednost. Stoga su desetice (20, 30, 40 itd.)
ispisane uz desni rub izlaza.
<r,
Napomena za VB programere: u C # se varijable iz petlje deklariraju
unutar zaglavlja iskaza fo r ili foreach a ne prije poetka iskaza. To
znai da su u dosegu samo unutar bloka i da ih se ne moe pozivati
izvan petlje. Iskaz foreach detaljnije je objanjen u poglavlju 9.
Treba istaknuti nekoliko stvari: u petlji for uvjet se testira prije izvoenja iskaza. Stoga se
u primjeru i inicijalizira kao 0, zatim se provjerava je li manje od 100. Budui da je iskaz
i < 1 0 0 toan, izvodi se iskaz unutar petlje for. Nakon izvoenja i se poveava (i++).
Upamtite da je d oseg varijable i unutar petlje for (to jest, varijabla i je vidljiva samo
unutar petlje for). Primjer 3-14 se nee prevesti.
using System;
using Systera.Collections.Generic;
using System.Text;
#endregion
namespace ForLoopScope
{ '
class ForLoopScope
{
s ta tic void Main( strin g[] args )
{
for ( int i = 0; i < 100; i++ )
{
Console.Write( "{0 } " , i ) ;
i f ( i % 10 == 0 )
{
Console.WriteLine( " \ t{ o j", i ) ;
}
}
Console.Writeline( "\n Final value of i: {o}", i );
}
}
}
i f (i%lo == o)
Console.WriteLine("\t{o}", i);
if ( i % 10 == o )
{
Console.WriteLine("Yt{o}", i);
}
}
Upotreba bjelina veinom je stvar osobnog ukusa. Visual Studio 2005 omoguava da
koritenje bijelog prostora konfigurirate odabirom opcije Tools -> Options -> C# ->
Formatting -* Spacing.
Iskaz foreach
Iskaz foreach je novina u porodici C jezika. On se koristi za petlje kroz elemente polja
ili kolekcije. Ovaj iznimno koristan iskaz detaljnije emo obraditi u poglavlju 9.
tirati
U primjeru 3-15 prikazana je mehanika iskaza continue i break. Ovaj kod mi je pred-
loio jedan od mojih recenzenata, Donald Xie, a slui razvoju sustava prometne signa-
lizacije. Signali se simuliraju unosom brojeva i velikih slova s pomou tipkovnice te
upotrebom Console.ReadLine() koja ita teksta s tipkovnice.
50 | Programiranje C#
IrniiS:
Algoritam je jednostavan: primitak nule znai normalne uvjete i daljnje akcije nisu
potrebne, osim za biljeenje dogaaja (u tom sluaju program jednostavno ispisuje
poruku na konzoli, a stvarna aplikacija mogla bi u bazu podataka unijeti zapis s vre-
menskom oznakom). Po primitku signala za prekid (simulira ga slovo ,,A) problem se
biljei i proces se prekida. Na kraju, za bilo koji drugi dogaaj pokree se alarm, koji
moda obavjetava policiju (ovaj primjer ne obavjetava policiju, ali ispisuje poruku
za uzbunu na konzoli). Ako je signal ,,X, pokree se alarm, ali se prekida i petlja
while.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace ContinueBreak
{
class ContinueBreak
{
static void Main( stringf] args )
{
string signal = "o"; // Inicijalizira s neutralnim stanjem
while ( signal != "X" ) // X oznaava zaustavljanje
{
Console.Write( "Enter a signal: " );
signal = Console.ReadiineO;
if ( signal == "A" )
{
// Pogreno - prekida obradu signala
// biljei problem i prekida.
Console.WriteLine( "Fault! AbortNn" );
break;
}
if ( signal == "o" )
{
// Normalno stanje
// biljei i nastavlja
Console.WriteLine( "Ali is well.\n" );
continue;
}
Svrha ove vjebe je pokazati kako se prilikom primanja signala Aizvodi akcija u iskazu
i f i zatim program izlazi iz petlje bez pokretanja alarma. Kad je signal 0, alarm se tako-
er ne treba pokrenuti te program nastavlja na poetku petlje.
Operatori
Operator je simbol koji uzrokuje da C # pokrene akciju. Primitivni tipovi (npr. int)
podravaju razne operatore kao to su pridruivanje, poveavanje i tako dalje.
Operator pridruivanja (= )
U ranijem odjeljku ovog poglavlja, Izrazi11, prikazana je upotreba operatora pridrui-
vanja. Ovaj simbol uzrokuje promjenu vrijednosti operanda s lijeve strane operatora
u vrijednost koja se nalazi s desne strane operatora.
Matematiki operatori
U C # koristi se pet matematikih operatora: etiri za standardne izraune i peti za vra-
anje ostatka pri dijeljenju cjelobrojne vrijednosti. Upotreba tih operatora objanjena
je u sljedeim odjeljcima.
52 | P ro g ra m ira n je C#
Operator modulo mnogo je korisniji nego to se to na prvi pogled ini. Kada upotrije-
bite modulo n na broju koji je viekratnik od n, rezultat je 0. Stoga je 80%10 = o jer je
80 cjelobrojni viekratnik od 10. Ta injenica omoguava postavljanje petlji u kojima
se akcija primjenjuje svaki n-ti put, testirajui na brojau je li %n jednako 0. Ova je
strategija korisna za petlju for, kao to je opisano ranije u ovom poglavlju. Utjecaj dije-
ljenja na cijele brojeve, brojeve s pominim zarezom, brojeve dvostruke preciznosti i
decimalne brojeve prikazanje u primjeru 3-16.
using System;
using System.Collections.Generic;
using System.Text;
endregion
namespace OivisionModulus
{
class DivisionModulus
{
static void Main( stringj] args )
{
int ii, i2;
float fl, f 2 ;
double dl, d2;
decimal decl, dec2;
11 = 17;
12 = 4;
fl = I7f;
f2 = 4f;
dl = 17;
' d2 = 4;
decl = 17;
dec2 = 4;
Console.WriteLine( "lnteger:\t{0}\nfloat:\t\t{l}",
ii / i2, fl / f2 );
Console.WriteLine( "double:\t\t{o}\ndecimal:\t{l}",
dl / d2, decl / dec2 );
Console.WriteLine( "\nModulus:\t{o}", ii % 12 );
1
}
}
Pogledajmo sljedei red iz primjera 3-16:
Console.WriteLine("Integer;\t{0 }\nfloat:\t\t{l}\n",
il/i2, fl/f2);
To e ispisati znakove Integ er:, zatim tabulator (Vt), prvi parametar ({o}) i znak za
novi red (\n). Sljedei odlomak niza:
floa t:\t\t{l} \ n
vrlo je slian. On ispisuje float:, zatim dva tabulatora (radi osiguravanja poravnanja),
sadraj drugog parametra ({ l}) i ponovno znak za novi red. Obratite panju i na slje-
dei red:
Console. WriteLine( "\nModulus:\t{ 0 } ", il%iz);
Ovaj put niz poinje znakom za novi red, to uzrokuje preskakanje reda tono prije
ispisa niza Modulus:.
i tako dalje.
Potreba za uveavanjem i umanjivanjem varijabli je toliko esta da C # sadri posebne
operatore za automatsko pridruivanje. U te se operatore ubrajaju +=, -=, /= i %= koji
kombiniraju zbrajanje, oduzimanje, mnoenje, dijeljenje i modulo s automatskim pri-
druivanjem. Stoga prethodne primjere moete napisati i na sljedei nain:
mySaJary += 5000;
mySalary *= 5000;
mySalary -= 5 0 0 0 ;
54 | P ro g ra m ira n je C#
Budui da je uveavanje i umanjivanje vrijednosti za 1 vrlo esta potreba, C # (kao i C
; C++) ima i dva posebna operatora. Za uveavanje vrijednosti za 1 koristite operator
++, a za umanjivanje vrijednosti za jedan koristite operator -
Stoga, ako varijablu myAge elite uveati za 1, moete napisati:
myAge++;
Kako biste dodatno zakomplicirali stvari, varijablu moete uveati i rezultat dodijeliti
drugoj varijabli:
firstValue = secondValue++;
Sad se postavlja pitanje elite li pridruivanje prije uveavanja vrijednosti ili nakon
njega? Drugim rijeima, ako secondValue poinje s vrijednosti 1 0 , elite li da na kraju
i firstValue i secondValue imaju vrijednost 11 ili elite da firstValue ima vrijednost 10
(poetna vrijednost), a da secondValue ima vrijednost 1 1 ?
C# (ba kao i C i C++) nudi dvije vrste operatora za uveavanje i umanjivanje: prefix
\sufx. Stoga moete napisati:
firstValue = secondValue++; // Sufiks
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace PrefixPostfix
{
class PrefixPostfix
{
static void Main( stringf] args )
{
int valueOne = 10;
int valueTwo;
valueTwo = valueOne++;
Console.WriteLine( "After postfix: {o}, {i}", valueOne,
valueTwo );
}
}
}
Relacijski operatori
Relacijski se operatori koriste za usporedbu dvije vrijednosti i vraaju Boolean vrijed-
nost (istinito ili neistinito). Operator vee od (>)vraa istinitu vrijednost ako je vrijed-
nost s lijeve strane operatora vea od vrijednosti s desne strane. Stoga 5>2 vraa true,
a 2>5 vraa -false.
Relacijski operatori jezika C # prikazani su u tablici 2-3. Ona pretpostavlja dvije vari-
jable: bigValue i smallValue, gdje bigValue ima vrijednost 100, a smallValue vrijednost
50.
bigValue != 80 true
56 | P ro g ra m ira n je C#
O perator pridruiva.nja (=) s. e esto mi>je----a----s-- Jo/pV e.UrVaVtoIUro1 1m
7-, jeUdUndat VkUobsltl i (==)
1 IV
D ru gi se saston od dva 7 naka ip r ln a ^ e ; -------
D gl Se sast0 , od dva znaka jed n akosti, a prvi od sam o jednog.
N E ! (x = 3) true
Operator I testira jesu li oba iskaza istinita. Prvi red u tablici 3 -4 sadri primjer koji
prikazuje upotrebu operatora I: y 1 J
(x == 3 ) && (y == 7 )
Kod operatora IL I jedna ili obje strane moraju biti istinite. Izraz je neistinit samo ako
su obje strane neistinite. Stoga, u sluaju primjera iz tablice 3-4:
(x = = 3 ) || (y == 7 )
(x - 3)
Prednost operatora
S a p L T < * < * * . A K Pri-
myVariable = 5 + 7 * 3 ;
Izravna procjena
P ogledajm o slje d e i o d lo m a k kod a:
int x = 8;
if ((* == 8) U (y 1 2 ))
Ovdje naveden iskaz i f pom alo je sloen. Cijeli iskaz i f nalazi se unutar zagrada,
kao i svi iskazi i f u jeziku C $ . Stoga, da bi iskaz i f bio istin iti, sve unutar vanjskih
zagrada mora biti istinito.
U nutar vanjskih zagrada nalaze se dva iskaza (x==8) i (y==l2), koji su odvojeni operato-
rom ILI (||). Budui da je x jedn ak o 8 , prvi iskaz (x 8) je istin it. Drugi iskaz (y==i2)
ne treba se provjeravati je r za istinitost cijelog izraza nije bitno je li y jedn a ko 12.
Pogledajmo i ovaj odlom ak koda:
in t x = 8;
if ((x == 5) && (y == 12))
Ponovno se drugi iskaz ne mora provjeravati. Budui da je prvi iskaz neistinit, I mora
im ati vrijednost neistinito (oba provjerena izraza m oraju biti istin ita kako bi iskaz I
bio istinit).
U ovakvim slu ajevim a, C # e skratiti provjeru. D rugo testiranje se uope nee
provesti.
Kategorija Operatori
Mnoenje + /%
Zbrajanje + -
Pomak
58 | P ro g ra m ira n je C#
Tablica 3-5- Prednost operatora (nastavak)
f kategorija Operatori
Relacijski < > < = > = isas
jednakost
Logiko I &
Logikoekskluzivno ILI A
Logiko ILI
Uvjetno I &&
Uvjetno ILI II
Uvjetni
Pridruivanje = *= / = + = -= = & = a = |=
U nekim sloenim jednadbama moda ete morati ugnijezditi zagrade kako biste
osigurali ispravan redoslijed operacija. Pretpostavimo da elite saznati koliko sekundi
moja obitelj izgubi svakog jutra. Ispostavlja se da odrasli svakog jutra potroe 20
minuta uz kavu i 10 minuta itajui novine. Djeca na ljenarenje potroe 30 minuta,
a na svau 10 minuta.
Evo mog algoritma;
(((minOrinkingCof-fee + minRead ing N ewspape r )* nu mAdu lts ) +
((minDaivdling + min Arguin g) * numChildren)) * secondsPerMinute.
lako ovaj algoritam funkcionira, teko ga je proitati i ispravno sastaviti. Sljedei nain
koritenja meuvarijabli mnogo je jednostavniji:
wastedByEachAdult = minDrinkingCoffee + minReadingNeivspaper;
wastedByAHAdults = wastedByEachAdult * numAdults;
wastedByEachKid = minDawdling + minArguing;
wastedByAUKids = wastedByEachKid * numChildren;
wastedByFamily = wastedByAllAdults + wastedByAllKids;
totalSeconds = wastedByFamily * 60;
U drugom se primjeru koristi mnogo vie varijabli, ali je taj primjer mnogo lake
proitati i razumjeti te (najvanije od svega) u njemu ispraviti pogreke. Prilikom pre-
gledavanja ovog programa alatom za ispravljanje pogreaka moete lako uoiti meu-
vrijednosti i provjeriti jesu li one ispravne.
Ternarni operator
Iako veina operatora zahtjeva jedan (npr. myValue++) ili dva izraza (npr. a+b) postoji
jedan operator koji zahtjeva tri: ternarni operator (?:):
uvjetni izraz ? izrazi : izraz2
Ovaj operator procjenjuje uvjetni izraz (izraz koji vraa vrijednost tipa bool), a zatim
poziva iz razi ako je uvjetni izraz vratio istinitu vrijednost ili izraz 2 ako je vraena nei-
stinita vrijednost. Logika je ako je ovo istinito, uini prvo, u suprotnom uini drugo".
To je prikazano u primjeru 3-18.
using System;
using System.Collections.Ceneric;
using System.Text;
#endregion
namespace TernaryOperator
{
class TernaryOperator
{
static void Main( string[] args )
{
int valueOne = 10;
int valueTwo = 2 0 ;
}
}
}
U Primjeru 3-18 ternarni se operator koristi za testiranje je li valueOne vee od valu-
eTwo. Ako je to sluaj, vrijednost valueOne se dodjeljuje cjelobrojnoj varijabli maxValue.
U suprotnom se vrijednost valueTwo dodjeljuje maxValue.
Naredbe za pretprocesor
U svim dosad navedenim primjerima prevodili ste cjelokupni program. Ponekad je,
meutim, potrebno prevesti samo dijelove programa - na primjer, ovisno o tome ispra-
vljate li pogreke ili prevodite finalni kod.
Prije nego to je kod preveden, pokree se drugi program koji se naziva pretprocesor
i priprema program za prevoditelj. Pretprocesor provjerava postoje li u kodu posebne
naredbe za pretprocesor koje uvijek poinju znakom ljestve (# ). Ove naredbe omogu-
avaju zadavanje identifikatora i testiranje njihova postojanja.
Definiranje identifikatora
Naredba #define DEBUG definira identifikator pretprocesora DEBUG. Iako se druge direk-
tive za pretprocesor mogu nalaziti bilo gdje unutar koda, identifikatori se moraju defi-
nirati prije svakog drugog koda, ukljuujui iskaze using.
60 | P ro g ra m ira n je C#
0
D d ^ n c Z C i C + + P m 8 m m e r e : C # P retprocesor primjenjuje s a m o
p o d s k u p C + + pretprocesora i ne podrava m a k r o naredbe.
#if DEBUG
// kod koji e biti ukljuen u uklanjanje pogreaka
#else
Jskaz i f pro vjerava p o sto ji li id e n tifik a to r DEBUG ko ji uistinu p o sto ji i stoga se kod
meu f , , 1 prevodi p,gram - ali se kod lzmeu , , ej di ' J J
Taj se kod uope ne pojavljuje u sklopu - kao da ga uope niste n. napisali. '
Dk i kaZ " t0 j6 S t ^ Ste t6Stlrali P St0ji H >de n tifik a to r koji n ije p o sto ja o
kod izm eu # i f i # e ls e se ne bi prevodio , za razliku od koda izm eu # i f i ifen dif.
**
r*&-
Pretprocesor ne utjee na kod koji se ne nalazi izmeu #if/#endif i on
t se prevodi u program.
ik '
#if DEBUG
// ovaj e se kod prevesti
#endif
#undef DEBUG
# if DEBUG
// ovaj kod se nee prevesti
#endif
#region
Naredba itregion polje teksta oznaava komentarom. Ona se u prvom redu upotre-
bljava da bi se alatima kao sto je Visual Studio .N ET omoguilo izdvajanje odreenog
dijela koda i njegovo saimanje u programu za ureivanje tako da se vidi samo naredba
itregion i njen komentar.
Kad, na primjer, piete Windows aplikaciju (sto je objanjeno u poglavlju 13), Visual
Studio stvara podruje za kod koji e upisati razvojni inenjer. Kad se podruje proiri,
ono izgleda poput podruja prikazanog na slici 3-3 (napomena: na slici je radi lakeg
snalaenja podruje istaknuto i oznaeno etverokutom).
Moete vidjeti podruje oznaeno naredbama itregion i ifendregion. Meutim, kad
podruje samete, vidjet ete samo komentar podruja (Windows Form Designer gene-
rated code), kao to je prikazano na slici 3 -4 .
62 | Programiranje C#
S' |f.-hyu'ii U irid ous Focin D e s i g n e r y-ru ;t.H L-d c o d e
D I .
t h i s . j U i t o S c a l e B u s e S i s e - ncw 5 ? s t e j n . l ov ikj S i . i t ( S , 1 3 ) ;
c U i a . C l i e n L 3 i c e " n t c S y s t c . P r a u m g . S i s e (2 5 2 , 2 7 3 ) ;
ibia.Neune - "Formi";
t b i 3 . T e x t ' " F o r m i" ;
t M s . L o a d +* n a v S y o r e i o . E v e n t H a n d l e r ( th l a . F o r m i L o a d ) ;
U poglavlju 3 objasnili smo primitivne tipove koji su dio jezika C# , poput in t, long
i char. Bit jezika C # zapravo je mogunost stvaranja novih, sloenih tipova koje defi-
nira sam programer, a koji jasno preslikavaju objekte od kojih se sastoji problem koji
pokuavate rijeiti.
Upravo je ova mogunost stvaranja novih tipova glavna karakteristika objektno orijen-
tiranih jezika. Nove tipove u jeziku C # zadajete deklariranjem i definiranjem klasa.
Tipove moete definirati i s pomou suelja (engl. interfaces ), to je detaljnije obja-
njeno u poglavlju 8. Instance klase nazivaju se objekti (engl. objects). Objekti se stva-
raju u memoriji prilikom izvoenja programa.
Razlika izmeu klase i objekta jednaka je razlici izmeu koncepta psa i stvarnog psa
koji vam moda sjedi kraj noge dok ovo itate. Definiciji psa ne moete baciti tap, to
moete uiniti samo s instancom.
Klasa Dog opisuje kakvi su psi: oni imaju svoju teinu, visinu, boju oiju, boju dlake,
narav i tako dalje. Karakteriziraju ih i akcije koje mogu izvesti, na primjer, mogu jesti,
hodati, lajati i spavati. Odreeni pas (npr. moj pas Milo) ima odreenu teinu (31 kg)
i visinu (55 cm), boju oiju (crna), boju dlake (uta), narav (pravi aneo) i tako dalje.
On ima iste sposobnosti kao svi psi (iako oni koji ga poznaju misle kako primjenjuje
samo metodu jedenja).
Ogromna prednost klasa u objektno orijentiranom programiranju je da su u njima
osobine i sposobnosti entiteta uahurene (engl. encapsulated ) u jedinstvenoj, samo-
stojnoj i samoodrivoj jedinici koda. Kada, na primjer, elite sortirati sadraj instance
padajueg popisa, samo popisu kaete da se sortira. Kako e to uiniti nije bitno - sve
to je bitno je da je sortiranje izvedeno. Uahurivanje, zajedno s polimorfizmom (engl.
polymorphism) i nasljeivanjem (engl. inheritance), je jedan od tri osnovna naela
objektno orijentiranog programiranja.
Stari programerski vic kae: Koliko je objektno orijentiranih programera potrebno
da bi se promijenila arulja? Odgovor: nijedan, arulji jednostavno kaete da se sama
promijeni (drugi odgovor: nijedan, Microsoft je standard promijenio na mrak).
64
I
U ovom su poglavlju opisane znaajke jezika C # koje se koriste za zadavanje novih
klasa. Elementi klase - ponaanja (engl. behaviors) i svojstva (engl. properties) - zajed-
niki se nazivaju lanovima klase (engl. class members). U ovom poglavlju opisat emo
kako se metode koriste za definiranje ponaanja klase i kako se stanje klase odrava u
varijablama lanicama (koje se esto nazivaju polja (engl.fields)). Pored toga, poglavlje
se bavi i svojstvima koja razvojnim inenjerima izgledaju poput metoda, a klijentima
klase kao polja.
Definiranje klasa
Za definiranje novog tipa ili klase prvo treba deklarirati, a zatim definirati pripadajue
metode i polja. Klasa se deklarira s pomou kljune rijei class. Potpuna sintaksa
glasi:
[atributi] [modifikator pristupa] class identifikator [:osnovna klasa [,suelja(e)]]
(tijelo klase}
U C# se sve dogaa unutar klase. Dosad, meutim, nismo instancirali nijednu instancu
klase; to jest, nismo stvorili nijedan objekt. Koja je razlika izmeu klase i instance te
klase? Kako bismo odgovorili na to pitanje, krenut emo od razlike izmeu tipa in t i
varijable tipa int. Moete, na primjer, napisati:
int mylnteger = 5;
no ne moete napisati:
int = 5;
Vrijednost se ne moe dodijeliti tipu. Ona se dodjeljuje objektu koji pripada tom tipu
(u ovom sluaju, varijabli tipa int).
Prilikom deklariranja nove klase programer definira svojstva svih objekata koji pripa-
daju toj klasi, kao i njihova ponaanja. Na primjer, stvarate li okoli s prozorima trebat
ete stvoriti standardne elemente prozora (u Windows programiranju oni se nazivaju
kontrole (engl. Controls)) kako biste korisniku pojednostavili interakciju s aplikacijom.
Jedna od zanimljivijih kontrola je padajui popis koji prikazuje niz opcija i korisniku
omoguava da odabere neke od njih.
Kad ste stvorili instancu ListBox, njenim poljima moete dodijeliti podatke.
Uzmimo za primjer klasu koja slui za praenje i prikaz vremena. Unutarnje stanje
klase mora moi prikazati tekuu godinu, mjesec, datum, sat, minutu i sekundu.
Vjerojatno ete htjeti da klasa vrijeme prikazuje u razliitim formatima. Takvu klasu
moete implementirati definiranjem jedne metode i est varijabli, kao to je prikazano
u primjeru 4-1.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace TimeClass
{
public class Time
{
// privatne varijable
int Vear;
int Month;
int Date;
int Hour;
int Minute;
int Second;
// javne metode
public void DisplayCurrentTime()
{
Console.WriteLine(
"stub for DisplayCurrentTime" );
}
}
66 | Programiranje C#
p imjer 4-1- J ednostavna ^ asa za Pokazivanje vremena (nastavak)
<*.
S
Prilikom prevoenja ove klase primit ete upozorenja o tome da se
varijable lanice Time (Vear, Mgnth itd.) nikad ne koriste. Zasad zanema-
*' rite ta upozorenja (iako upozorenja uglavnom nije dobro zanemarivati,
osim ako niste potpuno sigurni o emu se radi i zato ih moete zane-
mariti). U ovom sluaju pravimo samo kostur klase Time i, da se radi o
stvarnoj klasi, ove lanove bi koristili u drugim metodama.
Metoda DisplayCurrentTime() definirana je tako da vraa void tj. ona metodi koja ju
pozove nee vratiti vrijednost. Zasad je tijelo ove metode izbrisano.
D efinicija k la se Time zavrava d e k la ra c ijo m n e ko lik o v a rija b li la n ic a : Year, Month,
Date, Hour, Minute i Second.
Nakon zatvorene zagrade definira se druga klasa, Tester. Ona sadri ve poznatu
metodu Main(). U metodi Main() je stvorena instanca varijable Time i njena je adresa
dodijeljena objektu t . Budui d aje t instanca varijable Time, Main() moe s objektima
tog tipa iskoristiti metodu DisplayCurrentTime() i pozvati je kako bi se prikazalo vri-
jeme:
t.DisplayCurrentTime();
Modifikatori pristupa
Modifikator pristupa zadaje koje metode drugih klasa mogu vidjeti i koristiti odreenu
varijablu ili metodu unutar klase. U tablici 4-1 moete vidjeti saetak modifikatora
pristupa u jeziku C# .
private lanovima klase A koji su oznaeni modifikatorom p r i v a t e mogu pristupiti samo metode klase A.
protected lanovima klase A koji su oznaeni modifikatorom p r o t e c t e d mogu pristupiti metode klase A i
metode onih klasa koje su izvedene iz klase A.
internal lanovima klase A koji su oznaeni modifikatorom i n t e r n a l mogu pristupiti metode svih klasa
iz sklopa klase A.
Argumenti metoda
Metode mogu imati beskonaan broj param etara.' Popis parametara nalazi se iza
naziva metode unutar zagrada, a ispred svakog parametra stoji njegov tip. Sljedeom
se deklaracijom, na primjer, definira metoda MyMethod() koja vraa vrijednost void
(tj. ne vraa nikakvu vrijednost) i koja ima dva parametra: cjelobrojnu vrijednost i
gumb.
Termini argument" i parametar" se esto koriste za istu stvar iako neki programeri inzistiraju na razli-
kovanju deklaracije parametra i argumenta proslijeenih prilikom pozivanja metode.
68 | Programiranje C#
void MyMethod (int firstParam, Button secondParam)
{
II ...
}
Parametri unutar tijela metode funkcioniraju kao lokalne varijable, kao da ste ih dekla-
rirali u tijelu metode i inicijalizirali ih s proslijeenim vrijednostima. U primjeru 4-2
prikazan je nain prosljeivanja vrijednosti u metodu u ovom sluaju radi se o vri-
jednostima tipa int i float.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace PassingValues
{
public class MyClass
{
public void SomeMethodf int firstParam, float secondParam )
Console.Writeline(
"Here are the parameters received: {o}, {i}",
firstParam, secondParam );
}
}
Stvaranje objekata
U poglavlju 3 objanjena je razlika izmeu vrijednosnih tipova i referentnih tipova.
Primitivni tipovi jezika C # (in t, char itd.) su vrijednosni tipovi i stvaraju se na stogu.
Za razliku od njih, objekti su referentni tipovi i stvaraju se na gomili s pomou kljune
rijei new. Na primjer:
Time t = new Time();
a*
Napomena za VB6 programere: dok se u VB 6 kljune rijei Dim i Newne
bi trebale koristiti u istom redu jer to naruava izvedbu, u C # to nije
sluaj. Stoga u C # ne postoji zapreka koritenju kljune rijei new prili-
kom deklariranja varijable objekta.
Konstruktori
U primjeru 4-1 primijetit ete kako iskaz kojim se stvara objekt Time izgleda kao da
poziva metodu:
Time t = new Time();
Metoda se zapravo i poziva svaki put kad instancirate objekt. Ta se metoda naziva
konstruktor i morate ju definirati u okviru definicije klase ili dopustiti da je CLR osi-
gura umjesto vas. Zadatak konstruktora je stvaranje objekta koji je definiran klasom
i njegovo postavljanje u ispravno stanje. Prije pokretanja konstruktora objekt je samo
jo jedan dio memorije. Nakon to se konstruktor izvede u memoriji e stajati valjana
instanca klase type.
Klasa Time iz primjera 4-1 ne definira konstruktora. Ako konstruktor nije deklariran,
prevoditelj e ga sam pruiti. Podrazumijevani konstruktor stvara objekt, ali ne izvodi
nikakvu drugu akciju.
Varijable koje su lanice klase inicijaliziraju se u bezazlene vrijednosti (cjelobrojne vri-
jednosti se inicijaliziraju s nulom, nizovi s praznim nizom itd.).' U tablici 4-2 nalazi se
popis vrijednosti koje se podrazumijevano dodjeljuju primitivnim tipovima.
Kad piete vlastiti konstruktor vidjet ete da su vrijednosti inicijalizirane prije pokretanja konstruktora.
Postoje dva koraka u proesu stvaranja objekta - prvo se izvodi magija" na razini CLR-a koja resetira sva
polja i ini sve to je potrebno uiniti kako bi se napravio odgovarajui objekt i zatim se prelazi na kon-
struktor koji ste pruili (ako jeste).
70 | Programiranje C#
Tablica 4-2. Primitivni tipovi i njihove podrazumijevane vrijednosti
logiki False
enum o
reference nuli
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace DeclaiingConstructor
{
public class Time
{
Year = dt.Year;
Month = dt.Month;
Date = dt.Day;
Hour = dt.Hour;
Minute = dt.Minute;
Second = dt.Second;
}
}
public class Tester
{
static void Main()
{
System.DateTime currentTime = System.DateTime.Now;
Time t = new Time( currentTime );
t.DisplayCurrentTime();
}
}
}
U ovom primjeru konstruktor prihvaa objekt DateTime i inicijalizira sve pripadajue
varijable na temelju vrijednosti unutar objekta. Kad konstruktor zavri, objekt Time
postoji i vrijednosti su inicijalizirane. Kad se u Main() pozove DisplayCurrentTime(),
prikau se vrijednosti.
Pokuajte jedno od pridruivanja izdvojiti u komentar i ponovno pokrenuti program.
Vidjet ete kako je prevoditelj varijablu lanicu inicijalizirao u 0. Cjelobrojne varijable
lanice se postavljaju na 0 ako im ne dodijelite neku drugu vrijednost. Upamtite, inci-
jalizacija vrijednosnih tipova (npr. cjelobrojnih vrijednosti) se ne moe ponititi. Ako
ne zadate to konstruktor treba raditi, on e pokuati uiniti neto bezazleno.
U primjeru 4-3 objekt DateTime je stvoren u metodi Main() klase Tester. Ovaj objekt,
koji daje biblioteka System, nudi nekoliko javnih vrijednosti - Year, Month, Day, Hour,
Minute i Second - koje odgovaraju privatnim varijablama objekta Time. Uz to, objekt
DateTime nudi i statiko svojstvo Now koje je referenca instance objekta DateTime ini-
cijaliziranog s trenutnim vremenom.
Pogledajte istaknuti dio koda unutar Main() gdje je objekt DateTime stvoren pozivanjem
statikog svojstva Now. Now stvara vrijednost DateTime koja se u ovom sluaju kopira
u varijablu currentTime na stogu.
72 | Programiranje C#
Inicijalizatori
Vrijednosti varijabli lanica mogu se inic.jalizirati u incijalizatoru (engl. initializer)
umjesto u svakom konstruktoru. Inicijalizator moete stvoriti pridruivanjem poetne
vrijednosti elanu klase:
private int Second = 30; // inicijalizator
Pretpostavimo da je semantika naeg objekta Time takva da se, bez obzira na posta-
vljeno vrijeme, sekunde uvijek iniijaliziraju na 30. Kad bi klasu Time ponovno napisali
tako da koristi incijahzator, bez obzira na to koji se konstruktor pozove vrijednost
Second bi se uvijek micijalizirala eksplicitno s pomou konstruktora ili implicitno s
pomou lnicijanzatora. Pogledajte primjer 4-4.
ri r
U primjeru 4 -4 koristi se preoptereeni (engl. overloaded ) konstruktor,
<> 4 . ? .Zna<rI da P stoie dvije inaice konstruktora koje se razlikuju po
_ tk *. broju i tipu parametara. Preoptereeni konstruktori detaljnije su obja-
njeni kasnije u ovom poglavlju.
using System;
using System.Collections.Ceneric;
using 5ystem.Text;
kendregion
namespace Initializer
{
public class Time
{
// privatne varijable clanice
jirivate int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int Second = 30; // inicijalizator
11 konstruktori _
public Time( Sy st em . D at e T im e dt )
{
Year = dt.Vear;
Month = dt.Month;
Date = dt.Day;
Hour = dt.Hour;
Minute = dt.Minute; ....
Second = dt.Second; //eksplicitno pridruivanje
}
public Time( int Year, int Month, int Date,
int Hour, int Minute )
{
this.Year = Vear;
this.Month = Month;
this.Date = Date;
this.Hour = Hour;
this.Minute = Minute;
}
public class Tester
je s 3 0 :
private int Second = 30; // inicijalizator
viti na 30:
74 | Programiranje Ctt
jVfeutim, ako je Second dodijeljena vrijednost, kao to je to uinjeno u konstruktoru
(koji prihvaa objekt DateTime, podebljan u ispisu), ta e vrijednost zamijeniti inicija-
liziranu vrijednost.
Prilikom prvog pozivanja D isplay C urrentTim e() p o zivam o k o n stru k to r k o ji p rih v aa
objekt DateTime, a seku n de se in icija liz ira ju s 54. P rilik o m dru gog pozivanja poziva se
m etoda, izriito p o stav ljam o v rijem e na 1 1 :4 5 (b ez seku ndi) i dalje preuzim a in icija-
lizator.
Suelje ICloneable
.N E T kostur definira suelje IC lo n ea b le radi podrke konceptu konstruktora za kopi-
ranje (suelja su detaljnije obraena u poglavlju 8). Ovo suelje definira jednu jedinu
metodu: C lo n e (). Klase koje podravaju zamisao konstruktora za kopiranje trebale
bi implementirati IC lo n ea b le, a zatim implementirati ili plitku kopiju (pozivanje Mem-
berwiseClone) ili duboku kopiju (npr. pozivajui konstruktora za kopiranje i runo
kopirajui sve lanove).
class SomeType: ICloneable
{
public Object Clone()
{
return MemberwiseClone(); // plitka kopija
}
}
Pokaziva je varijabla koja sadri adresu objekta u memoriji. C# ne koristi pokazivae s upravljivim objek-
tima. Neki C++ programeri toliko su se navikli na pokaziva this da ga (neispravno) koriste i u C#.
Dobra strana ovakvog stila je odabir dobrog naziva varijable koji se zatim koristi i za
parametar i za varijablu lanicu. Loa je strana koritenje istog naziva za parametar i
varijablu lanicu, to ponekad moe biti zbunjujue.
Drugi nain upotrebe reference th is je prosljeivanje trenutnog objekta kao parametra
u drugu metodu. Na primjer:
class myClass
76 | Programiranje C#
U navedenim primjerima koritenje reference this je suvino, ali moe dodatno poja-
sniti namjeru programera, a da pritom ne uini nikakvu tetu (osim mogueg optere-
enja koda).
a ne:
btnUpdate.SomeMethod();
Statike metode ne mogu izravno pristupiti lanovima koji nisu statiki. Kako bi
metoda Main() pozvala metodu koja nije statika, ona mora instancirati objekt. Pogle-
dajte ranije navedeni primjer 4-2.
SomeMethod() je nestatika metoda MyClass. Kako bi Main() pristupila toj metodi, ona
prvo mora instancirati objekt tipa MyClass i zatim pozvati metodu kroz taj objekt.
Zapravo, CLR jami da e pokrenuti statiki konstruktor prije b ilo k a k v e operacije s klasom. Dalje, on
samo jami da e p okren u ti izvoenje konstruktora, ali ne i da e zav riti njegovo izvoenje. Mogue je
zamisliti primjer u kojem su dvije klase ovisne jedna o drugoj. Umjesto da ue u slijepu ulicu, CLR moe
pokrenuti konstruktore u razliitim dretvama tako da ispuni jamstvo da e bar zapoeti izvoenje kon-
struktora pravilnim redoslijedom.
78 | Programiranje C#
Prim ijetit e te k a k o ispred sta ti k o g ko n stru kto ra nem a m od ifik ato ra pristu pa (npr.
public). K o rite n je m o d ifik a to ra p ristu pa uz sta ti k e k o n stru k to re n ije d op u ten o.
Nadalje, b u du i da se radi o sta tiko j m etodi la n ici, ne m o ete p ristu piti v arijab la m a
lanicama k o je nisu sta ti k e pa se Name m ora de klarira ti k a o sta tika v arijabla:
private static string Name;
Statike klase
U C# ne postoje globalne metode ili konstante. Moda ete morati stvarati male
pomone klase ija je jedina svrha da sadravaju statike lanove. Zanemarimo li
posljedice tog postupka, ako uistinu stvorite takvu klasu, trebat ete izbjei stvara-
nje instanci. Klasu oznaite sa S t a t i c kako biste osigurali da se nee stvoriti nijedna
instanca klase. Statike su klase zapeaene i stoga se ne mogu stvoriti izvedeni tipovi
klase S t a t i c . Upamtite kako statike klase ne moraju sadravati nestatike lanove ili
imati konstruktor.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace StaticFields
{
public class Cat
{
private static int instances = 0;
public Cat()
{
instances++;
}
80 | Programiranje C#
Statike metode za pristup statikim poljima
Podatke lanove nije dobro oznaiti s public. To se odnosi i na statike varijable la-
nice. Jedn o je rjeenje oznaiti statikog lana s p rivate, kao to smo to m aloprije
uinili s instartces. Stvorena je javna metoda HowManyCats() koja omoguava pristup
ovom privatnom lanu.
Unitavanje objekata
Budui da C # osigurava sakupljanje otpada, objekte ne morate sami unitavati. Meu-
tim, ako objekt kontrolira neupravljive resurse, te resurse ete morati eksplicitno oslo-
boditi kad vam vie nisu potrebni. Implicitnu kontrolu neupravljivih resursa omogu-
ava destruktor kojeg sakuplja otpada poziva kada je objekt uniten.
-**r----
Napomena za C i C++ programere: destruktor se ne pozva obavezno
4, nakon to objekt izae iz dosega, ve kad bude sakupljen kao otpad
TL-*. (to se moe dogoditi mnogo kasnije). To se naziva i nedeterministika
finalizacija.
C# destruktor
Destruktor jezika C # sintaktiki nalikuje C++ destruktoru, no ponaa se drugaije.
C# destruktor deklarirajte znakom tilda, na sljedei nain:
~MyClass(){}
Veinu vremena neete trebati izravno stvarati klase koje slue za rad s neupravljivim resursima poput
sirovih identifikatora. Moda ete, meutim, koristiti klase omotae poput FileStream ili Socket, ali te
klase ne implementiraju IDisposable pa u tom sluaju trebate u klasi implementirati IDisposable (ali ne i
finalizator). Metoda Dispose e za sve resurse koji se trebaju ukloniti pozvati Dispose.
82 1 Programiranje C#
"Not in destructor, OK to reference other objects");
}
// izvodi ienje za ovaj objekt
Console.WriteLine("Disposing..
}
this.is_disposed = true;
}
public void Dispose()
{
Dispose(true);
// govori sakupljau otpada da ne finalizira
GC.SuppressFinalize(this);
}
~Testing()
{
Dispose(false);
Console.WriteLine(In destructor.);
}
}
Iskaz using
Kako bi klijenti lake ispravno odloili objekte, u C# je dostupan iskaz using koji osi-
gurava najranije mogue pozivanje metode Dispose(). Trebate deklarirati objekte koje
koristite i zatim napraviti doseg za njih s pomou vitiastih zagrada. Kada se dosegne
zatvorena vitiasta zagrada automatski e se pozvati metoda Dispose() za objekt, kao
to je prikazano u primjeru 4-6.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
#endregion
namespace usingStatement
{
class Tester
{
using ( anotherFont )
{
// koristi anotherFont
U drugom dijelu primjera objekt Font je stvoren izvan iskaza using. Kada odluimo upo-
trijebiti upravo to pismo stavljamo ga unutar iskaza using. Kad iskaz zavri, ponovno
se poziva Dispose ().
Drugi je pristup prilino opasan. Ako se izbaci iznimka nakon stvaranja objekta, no
prije poetka bloka using, objekt se nee odloiti. Drugo, varijabla ostaje u dosegu i
nakon zavretka bloka using, no ona nee uspjeti ako joj se pristupi.
Iskaz using titi i od neoekivanih iznimki. Dispose() se poziva bez obzira na to kako
kontrola naputa iskaz using. Stvara se implicitni blok try-finally (pogledajte pogla-
vlje 11 za vie informacija).
Prosljeivanje parametara
Prema zadanim postavkama vrijednosni tipovi se u metode prosljeuju po vrijednosti.
To znai da se, prilikom prosljeivanja objekta vrijednosti metodi, unutar te metode
stvara privremena kopija objekta. Kad metoda zavri, kopija se unitava. Iako je pro-
sljeivanje po vrijednosti uobiajen postupak, ponekad se objekti prosljeuju i po refe-
renci. C # za prosljeivanje objekata vrijednosti u metodu po referenci nudi parametar
ref, a za prosljeivanje varijable ref bez prethodne inicijalizacije postoji modifikator
out. C # podrava i modifikator params koji metodi doputa prihvaanje promjenjivog
broja parametara. Kljuna rije params poblie je objanjena u poglavlju 9.
84 | Programiranje C#
Prosljeivanje po referenci
M e t o d e m o g u vratiti s a m o j e d n u vrijednost (iako ta vrijednost m o e biti kolekcija vri-
jednosti). P o g l e d a j m o p o n o v n o k l a s u Time i m e t o d u GetTitne() koj a v ra a sate, m i n u t e
isek unde.
using System;
using System.Collections.Generic;
using System.Text;
ffendregion
namespace ReturningValuesInParams
{
public class Time
{
// privatne varijable lanice
private int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int Second;
h = Hour;
m = Minute;
int theHour = 0;
int theMinute = 0;
int theSecond = 0;
t.GetTime( theHour, theMinute, theSecond );
System.Console.WriteLine( "Current time: {0}:{l}:{2}",
theHour, theMinute, theSecond );
}
}
}
Obratite pozornost Current time u izlazu je 0:0:0. Ovaj pokuaj oito nije dao eljene
rezultate. Problem je u parametrima. U GetTime() se prosljeuju tri cjelobrojna para-
metra, zatim se parametri u GetTime() modificiraju, ali kad se vrijednostima ponovno
pristupi u Main() one nisu promijenjene. To se dogodilo zbog toga to cijeli brojevi
pripadaju vrijednosnom tipu, to znai da se prosljeuju po vrijednosti; u GetTime()
se nalazi kopija. Mi te vrijednosti trebamo proslijediti po referenci.
Za to su potrebne dvije male promjene. Prvo parametre metode GetTime() promijenite
tako da oznaavaju kako se radi o parametrima ref:
public void GetTime(re-f int h, ref int m, ref int s)
{
h = Hour;
m = Minute;
s = Second;
}
86 | Programiranje C#
Z a t i m modificirajte p oz i v GetTime() k a k o bi se i a r g u m e n t i proslijedili p o referenci:
Ako izostavite drugi korak u kojem se argumenti oznaavaju kljunom rijei ref, pre-
voditelj e javiti da se argument ne moe pretvoriti iz int u ref int.
Novi rezultat pokazuje tono vrijeme. Deklariranjem parametara kao ref parametara
prevoditelju dajete uputu da ih proslijedi po referenci. Umjesto stvaranja kopije, para-
metar u GetTime() je referenca do iste varijable (theHour) koja je stvorena u Main().
Kada te vrijednosti promijenite u GetTime(), promjena e se odraziti i u Main().
Inicijalizacija ovih vrijednosti ini se beskorisnom jer ih odmah prema referenci pro-
sljeujete GetTime gdje e se promijeniti. No, ako to ne uinite, javit e se sljedee
pogreke prevoditelja:
Use of unassigned local variable 'theHour'
Use of unassigned local variable 'theMinute'
Use of unassigned local variable 'theSecond'
h = Hour;
m = Minute;
s = Second;
}
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace InOutRef
{
public class Time
{
// privatne varijable lanice
private int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int Second;
public void SetTime( int hr, out int min, ref int sec )
{
// ako je proslijeeno vrijeme >= 30
// poveava minute i postavlja sekunde na o
// u suprotnom ne mijenja nita
if ( sec >= 30 )
{
Minute++;
Second = 0;
}
88 | Programiranje C#
Primjer 4-8. Koritenje parametara in , o u t i r e f (nastavak)
Hour = hr; // postavlja na proslijeenu vrijednost
}
// konstruktor
public Time( System.DateTime dt )
{
Year = dt.Year;
Month = dt.Month;
Date = dt.Day;
Hour = dt.Hour;
Minute = dt.Minute;
Second = dt.Second;
}
}
public class Tester
{
static void Main()
{
System.DateTime currentTime = System.DateTime.Now;
Time t = new Time( currentTime ); t
.DisplayCurrentT ime();
int theHour = 3;
int theMinute;
int theSecond = 2 0 ;
theSecond = 40;
t.SetTime( theHour, out theMinute, ref theSecond );
System.Console.WriteLine( ''the Minute is now: " +
"{0 } and {l} seconds",
theMinute, theSecond ); -
}
}
}
SetTime izgleda pomalo neprirodno, ali prikazuje sva tri tipa parametara. theHour se
prosljeuje kao parametar vrijednosti. Njegova jedina funkcija je postavljanje varijable
lanice Hour i s pomou tog se parametra ne vraa nikakva vrijednost.
ref parametar theSecond se koristi za postavljanje vrijednosti u metodi. Ako je theSe-
cond vei ili jednak 30 , varijabla lanica Second se ponovno postavlja na nulu a varijabla
lanica Minute se poveava.
Klasa moe imati neogranien broj metoda, ali se njihovi potpisi moraju meusobno
razlikovati.
U primjeru 4-9 prikazana je klasa Time sa dva konstruktora: jednim koji prihvaa
objekt DateTime i drugim koji prihvaa est cjelobrojnih vrijednosti.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace OverloadedConstructor
{
90 | Programiranje C#
p n m j e r 4-9. P r e o p t e r e iv a n j e k o n s t r u k t o r a ( n a s t a v a k )
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace VaryingReturnType
{
public class Tester
{
private int Triple( int val )
{
return 3 * val;
}
private long Triple( long val )
{
return 3 * val;
)
public void Test()
{
int x = 5;
int y = Triple( x );
System.Console.Writeline( "x: {0} y: {l}", x, y );
long lx = 1 0 ;
' long ly = Triple( lx );
System.Console.WriteLine( "lx: {o} ly: {l}", lx, ly );
}
static void Main()
{
Tester t = new Tester();
92 | Programiranje C#
* Primjer 4-10. Preoptereivanje metode s razliitim povratnim tipovima (nastavak)
t.Testf);
}
}
}
u ovom primjeru klasa Tester preoptereuje metodu T riple(), tako da jedna prihvaa
cjelobrojnu vrijednost, a druga long. Dvije metode Triple() imaju razliite povratne
tipove. Iako to nije obavezno, u ovom sluaju je vrlo korisno.
Odvajanjem stanja klase od metode koja tom stanju pristupa, dizajner moe prema
potrebi promijeniti unutarnje stanje objekta. Prilikom prvog stvaranja klase Time, vri-
jednost Hour mogla bi se spremiti kao varijabla lanica. Kad se klasa prepravi, vrijed-
nost Hour moe se izraunati ili preuzeti iz baze podataka. Ako klijent ima izravan
pristup izvornoj varijabli lanici Hour, prebacivanje na izraun vrijednosti prekinulo
bi njegov rad. Odvajanjem i prisiljavanjem klijenta da proe kroz metodu (ili svojstvo)
klasa Time moe promijeniti nain na koji upravljanja internim stanjem bez naruava-
nja koda klijenta.
Svojstva zadovoljavaju oba uvjeta: klijentu pruaju jednostavno suelje jer izgledaju
kao varijable lanice. Meutim, implementiraju se kao metode, omoguavajui sakri-
vanje podataka koje zahtijeva dobar objektno orijentiran dizajn, kao to je prikazano
u primjeru 4-11.
using System;
using System.Collections.Generic;
using System.Text;
Dendregion
namespace UsingAProperty
{
System . C on so le . W ri te Li ne(
"TimeVt: {0}/{l}/{2} {3}:{4}:{5}",
month, date, year, hour, minute, second );
}
// konstruktori
public Time( S y s t em . D at e T im e dt )
{
year = dt.Year;
month = dt.Month;
date = dt.Day;
hour = dt.Hour;
minute = dt.Minute;
second = dt.Second;
}
// stvara svojstvo
set
{
hour = value;
}
}
}
public class Tester
{
static void Main()
th eHour );
94 | Programiranje C#
primjer 4-11. Koritenje svojstva (nastavak)
theHour++;
t.Hour = theHour;
System.Console.WriteLine( "Updated the hour: {0}\n", theHour );
}
}
}
2a deklariranje svojstva napiite tip i naziv svojstva i iza njih stavite par vitiastih
zagrada. Unutar zagrada moete deklarirati pristupnike (engl. accessors) get i set, Nije-
dan od njih nema eksplicitne parametre, iako metoda se t() ima implicitni parametar
value, kao to je prikazano u sljedeem primjeru.
U primjeru 4-11, Hour je svojstvo. Deklaracija tog svojstva stvara dva pristupnika: get
i set.
public int Hour
{
get
{
return hour;
}
set
{
hour = value;
}
1
Svaki pristupnik ima svoje tijelo koje uzima i postavlja vrijednost svojstva. Vrijednost
svojstva moe biti pohranjena u bazi podataka (u tom e sluaju glavni dio pristupnika
uiniti ono to je potrebno za interakciju s bazom podataka) ili moe biti pohranjena
u privatnoj varijabli lanici;
private int hour;
Pristupnik get
Tijelo pristupnika get slino je metodi klase koja vraa objekt tipa svojstva. Svojstvo
Hour iz navedenog primjera slino je metodi koja vraa in t. Ono vraa vrijednost pri-
vatne varijable lanice u kojoj je pohranjena vrijednost svojstva:
get
{
return hour;
}
U ovom primjeru vraa se lokalna varijabla lanica int, ali mogli biste isto tako uzeti
cjelobrojnu vrijednost iz baze podataka ili je izraunati.
Prilikom svakog itanja svojstva poziva se pristupnik get;
Time t = new Time(currentTime);
int theHour = t.Hour;
P ristu p n ik set
Pristupnik set postavlja vrijednost svojstva i slian je metodi koja vraa void. Prilikom
definiranja pristupnika set morate koristiti kljunu rije value koja e predstavljati
argument ija se vrijednost prosljeuje i koju svojstvo sprema:
set
{
hour = value;
}
U ovom se primjeru ponovno za spremanje vrijednosti svojstva koristi privatna vari-
jabla lanica, no pristupnik set moe prema potrebi zapisivati u bazu podataka ili
aurirati druge varijable lanice.
Kada svojstvu dodijelite vrijednost, automatski se poziva pristupnik set te se impli-
citni parametar value postavlja na vrijednost koju dodijelite:
theHour++;
t.Hour = theHour;
Dvije glavne prednosti ovog pristupa su to klijent moe izravno raditi sa svojstvima,
bez rtvovanja neprikosnovenosti sakrivanja podataka i uahurivanja u dobrom
objektno orijentiranom programiranju, te mogunost da autor svojstva osigura valja-
nost podataka.
96 | Programiranje C#
Polja readonly
, vi Moda ete trebati stvoriti inaicu klase Time koja e pruati javne statike vrijednosti
d--"' kkojeo j e e pred
r stavljati tekue vrijeme i datum. U primjeru 4-12 ilustriran je
jednostavan
i^ p g r is tu p ovom problemu.
using System;
using Sys tem.Coll ections.C e n e r i c ;
\ using Sy stem .Tex tJ
. Sendregion
. namespace StaticPublicConstants
{'
public class RightNow
, {
// javne varijable lanice
public static int Year;
public static int Month;
public static int Date;
| public static int Hour;
public static int Minute;
public static int Second;
static RightNow()
{
System.DateTime dt = System.DateTime.Now;
Year = dt.Year;
Month = dt.Month;
Date = dt.Day;
, Hour = dt.Hour;
Minute = dt.Minute;
Second = dt.Second;
}
}
}
. 1
Bilo bi dobro statike vrijednosti oznaiti kao konstante, ali to nije mogue jer se one
inicijaliziraju tek kad se izvede statiki konstruktor. U C# za ovu svrhu postoji kljuna
rije readonly. Ako deklaracije varijabli lanica klase promijenite na sljedei nain:
public static readonly int Year;
public static readonly int Month;
public static readonly int Date;
public static readonly int Hour;
public static readonly int Minute;
public static readonly int Second;
98 I Programiranje C#
POGLAVLJE 5
Nasljeivanje i polimorfizam
U prethodnom smo poglavlju pokazali kako se novi tipovi mogu stvoriti deklariranjem
klasa. Ovo poglavlje bavi se odnosom izmeu objekata iz stvarnog svijeta i modelira-
njem tih odnosa u kodu. Glavna tema ovog poglavlja je specijalizacija koja se u jeziku
C# implementira s pomou nasljeivanja. U ovom je poglavlju objanjeno i kako se
instance vie specijaliziranih klasa mogu tretirati kao da je rije o instancama opih
klasa, a taj se postupak naziva polimorfizmom (engl. polymorphism). Poglavlje zavr-
ava objanjenjem zapeaenih klasa koje se ne mogu specijalizirati: apstraktnih klasa
koje postoje samo kako bi se specijalizirale te korijena svih klasa, klase Object.
Specijalizacija i generalizacija
Klase i njihove instance (objekti) ne postoje u vakuumu, ve u mrei meusobne ovi-
snosti i odnosa, kao to mi, drutvene ivotinje, ivimo u svijetu odnosa i kategorija.
Odnos to je je jedna vrsta specijalizacije. Kada kaemo kako je pas sisavac, to znai
kako je pas specijalizirana vrsta sisavca. On ima sve osobine sisavca (raa ive mlade,
doji ih mlijekom, ima dlaku), ali su te osobine specijalizirane na poznate osobine poro-
dice canine domesticus. Maka je takoer sisavac. Iz toga moemo zakljuiti da make
i psi imaju neke zajednike osobine koje pripadaju opim osobinama sisavaca, ali se
make i razlikuju od pasa u onim osobinama koje su specijalizirane za make.
Odnosi specijalizacije i generalizacije su proporcionalni i hijerarhijski. Proporcionalni
su jer je specijalizacija suprotno od generalizacije. Stoga su pas i maka specijalizacije
sisavca, a sisavac je generalizacija psa i make.
Ti su odnosi i hijerarhijski jer ine stablo odnosa u kojem se specijalizirani topovi f
granaju iz vie generaliziranih tipova. to se po hijerarhiji vie pomiete prema gore, |
to j e generalizacija vea. Kako biste generalizirali osobinu da i make i psi raaju ive j
mlade, pomiete se do sisavaca. Pomicanje kroz hijerarhiju prema dolje predstavlja j
specijalizaciju. Stoga je maka specijalizacija sisavca koja ima pande (osobina) i prede
(ponaanje). |
Slino tome, ako kaete da ListBox i Button jesu Controls, naznaujete kako Controls i
imaju osobine i ponaanja koja se mogu pronai u oba tipa. Drugim rijeima, Control "
generalizira zajednike osobine ListBox i Button, dok ListBox i Button specijaliziraju
posebne osobine i ponaanja.
0 UML-u
Unified Modeling Language (UML) je standardizirani jezik za opis sustava ili
naina poslovanja. Dio UML-a koji je koristan za svrhe ovog poglavlja je skup dija-
grama koji se koriste za dokumentiranje odnosa izmeu klasa.
U UML-u klase su predstavljene okvirima. Naziv klase nalazi se na vrhu okvira, a
(prema izboru) metode i lanovi se mogu popisati unutar okvira. U UML-u se odnosi
specijalizacije (na primjer) modeliraju na nain prikazan na slici 5-1. Strelica kree iz
klase koja je specijalizirana i pokazuje generaliziranu klasu.
100 | Programiranje C#
Slika 5-2. Izvoenje iz Control
Ovaj UML dijagram prikazuje odnos izmeu klasa i pokazuje kako su i klasa ListBox
i Button izvedene iz Control, a da je klasa Button dalje specijalizirana u klase CheckBox
i Command. Nadalje, klasa RadioButton je izvedena iz CheckBox. Moete, dakle, rei kako
RadioButtonjest CheckBox koji je Button, a Buttons su Controls.
Ovo nije jedina, niti vjerojatno najbolja, organizacija ovih objekata, ali predstavlja
dobar uvod u prikaz meusobnih odnosa tipova (klasa).
<*
Implementacija nasljeivanja
U C # se izvedena klasa stvara dodavanjem dvotoke iza naziva izvedene klase, iza
ega slijedi naziv osnovne klase:
public class ListBox : Control
Ovim se kodom deklarira nova klasa ListBox koja izvodi iz klase Control. Dvotoka
se moe proitati kao izvodi iz.
a *
Napomena za C++ programere: u C# ne postoji privatno i zatieno
nasljeivanje.
Izvedena klasa nasljeuje sve lanove osnovne klase - varijable i metode lanice.
Polimorfizam
Nasljeivanje ima dva vana aspekta. Jedan je ponovna upotreba koda. Kada stvorite
klasu ListBox moi ete ponovno upotrijebiti dio logike iz osnovne klase (Control).
Drugi aspekt nasljeivanja moda je jo vaniji: to je polimorfizam. Poli znai mnogo,
a m orf znai oblik. Polimorfizam dakle predstavlja mogunost koritenja vie oblika
tipa, bez obzira na njihove pojedinosti.
Kada telefonska kompanija vaem telefonu poalje signal zvona, ona ne zna kakav se
tip telefona nalazi na drugoj strani linije. Moda imate starinski telefon u kojem pose-
ban motor pokree zvono, a moda imate elektronski telefon ije je zvonjenje zapravo
digitalna glazba.
Vaa telefonska kompanija poznaje samo osnovni tip Phone i oekuje da svaka
instanca" ovog tipa moe zvoniti. Kad telefonska kompanija vaem telefonu naredi
da zazvoni, ona od telefona jednostavno oekuje da uini pravu stvar". Telefonska
kompanija va telefon, dakle, tretira polimorfno.
102 | Programiranje C#
' Control iz primjera 5-1 oznaili kao polimorfnu, jednostavno u njenu deklaraciju
dodajte kljunu rije Virtual na sljedei nain:
public Virtual void DrawWindow()
Sada e svaka izvedena klasa moi implementirati vlastitu inaicu DrawWindow(). Kako
biste to uinili, jednostavno premostite virtualnu metodu osnovne klase koristei
kljunu rije override u definiciji metode izvedene klase i zatim dodajte novi kod za
tu premoenu metodu.
Usljedeem odlomku iz primjera 5-1 (koji je naveden kasnije u ovom odjeljku) ListBox
je izvedena iz Control i implementira vlastitu inaicu metode DrawWindow():
public override void DrawWindow()
{
base.DrawWindow(); // poziva osnovnu metodu
Console.WriteLine ("Writing string to the listbox: {o}",
listBoxContents);
}
Kljuna rije override prevoditelju govori da je ova klasa namjerno premostila nain
rada metode DrawWindow(). Na slian je nain ova metoda premoena i u drugoj klasi,
Button, koja je takoer izvedena iz Control.
U tijelu primjera 5-1 prvo ete stvoriti tri objekta: Control, ListBox i Button. Zatim ete
za svaki od njih pozvati metodu DrawWindow():
Control win = new Control(l,2);
ListBox lb = new ListBox(3,4,"Stand alone list box")j
Button b = new Button(5,6);
win.DrawWindow();
lb.DrawWindow();
b.DrawWindow();
Prvi element polja ima indeks 0. Koritenje polja u ovom primjeru trebalo
bi biti prilino intuitivno. Polja su iscrpnije objanjena u poglavlju 9.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace VirtualMethods
{
public class Control
{
// Ovi lanovi su zatieni i zbog toga vidljivi
// metodama izvedene klase. 0 tome emo
// detaljnije govoriti kasnije u poglavlju,
protected int top;
protected int left;
{
Console.WriteLine( "Control: drawing Control at {o}, {l}",
top, left );
}
}
104 | Programiranje C#
r 5 -1 . Koritenje virtualnih metoda (nastavak)
{
listBoxContents = contents;
* )
public Button(
int top,
int left ):
base(top, left)
{
}
}
}
}
}
U cijelom su primjeru nove premoene metode oznaene kljunom rijeci overnde:
public override void DrawWindow()
P revoditelj sada zna k o ristiti p re m o e n u m eto d u k o d p o lim o rfn e o b ra d e ov ih obje-
k a ta . P revoditelj je odgovoran za p ra e n je stv a rn o g tip a o b je k ta i za ru k o v a n je kasnim
povezivanjem 11 ta ko da se ListBox.DrawWindow() poziva kad referen ca C o n tro l zapravo
p o ka z u je na o b je k t ListBox.
106 1 Programiranje C#
Jf *
Kao to je objanjeno u poglavlju 4, ako ne deklarirate nikakav kon-
struktor, prevoditelj e za vas stvoriti podrazumijevani konstruktor.
Bilo da ga sami napiete, ili koristite jedan od konstruktora koje je
pruio prevoditelj, podrazumijevani konstruktor je onaj koji ne uzima
parametre. Meutim, kada stvorite bilo kakav konstruktor (sa ili bez
parametara), prevoditelj nee umjesto vas stvoriti podrazumijevam
konstruktor.
Kontrola pristupa
Vidljivost klase i njenih lanova moe se ograniiti koritenjem modifikatora pristupa
kao to su public, private, protected, internal i protected internal (objanjenje modi-
fikatora pristupa potraite u poglavlju 4).
Kao to ste ve vidjeli, public doputa da lanu pristupe metode lanice drugih klasa,
dok private oznaava da je lan vidljiv samo metodama lanicama svoje klase. Kljuna
rije protected vidljivost proiruje ne metode izvedenih klasa, dok je internal proi-
ruje na metode svih klasa iz istog sklopa.'
Par kljunih rijei internal protected doputa pristup lanovima istog sklop (inter-
nal) ili izvedenih klasa (protected). Ovu oznaku moete shvatiti i kao internal ili
protected.
Klase se, isto kao i njihovi lanovi, mogu oznaiti bilo kojim od navedenih modifika-
tora pristupa. Ako lan klase ima drugaiji modifikator pristupa od klase, primjenjuje
se modifikator koji namee vee ogranienje. Stoga, ako klasu myClass definirate na
sljedei nain:
public class myClass
{
U ...
protected int myValue;
} .
pristup myValue je ogranien iako je sama klasa oznaena kao javna .Javna klasa je vidljiva
svim ostalim klasama koje joj ele pristupiti. esto se stvaraju klase ija je jedina svrha
pomoi drugim klasama u sklopu, a te je klase bolje oznaiti s internal nego s public.
Sklop (kao to je objanjeno u Poglavlju 1) je jedinica dijeljenja i ponovnog koritenja koda u CLR-u
(logiki DLL). Sklop se obino stvara od skupa fizikih datoteka koje se nalaze u jednoj mapi koja sadri
sve resurse (bit mape, .g if datoteke itd.) potrebne za izvedbenu datoteku, zajedno slL-om i metapodacima
za taj program.
{ i
public Virtual void Sort() {...} 1
} i
To ne predstavlja nikakav problem dok Tvrtka A, autor klase Control, ne izda inaicu j
2 svoje klase Control i ispostavi se da su i programeri Tvrtke A dodali metodu Sort() j
svojoj javnoj klasi Control:
public class Control
{
// ...
public Virtual void Sort() {...}
}
U drugim objektno orijentiranim jezicima (npr. u C++) nova virtualna metoda Sort() -
funkcionirala bi kao osnovna metoda za virtualnu metodu So rt() u ListBox. Prevodi-
telj bi pozvao metodu S ort() iz ListBox kad ste zapravo namjeravali pozvati metodu
S o rt() iz Control. U Java jeziku, ako So rt() iz Control ima drugi povratni tip,program
za uitavanje klase bi smatrao da je S o rt() iz ListBox nepravilno premoivanje i ui-
tavanje ne bi uspjelo.
C # sprjeava ovaj problem. Virtualna metoda se u C # uvijek smatra za korijen vir-
tualnog otpremanja tj. kad C # pronae virtualnu metodu on prestaje s traenjem uz
hijerarhiju nasljeivanja. Ako je u Control uvedena nova virtualna metoda Sort(),
ponaanje ListBox tijeko izvedbe ostaje nepromijenjeno.
Kada se ListBox ponovno prevede prevoditelj generira upozorenje:
...\classl.cs(54,24): warning CS0114: 'ListBox.Sort()' hides
inherited member 'Control.Sort() .
To make the current member override that implementation,
add the override keyword. O t h e m i s e add the new keyword.
108 | Programiranje C#
-><Ova akcija uklanja upozorenje. Ako, s druge strane, programer eli premostiti metodu
tontrol, treba samo s pomou kljune rijei override naznaiti kako se radi o eks-
nam)en;
I public class ListBox : Contiol
i . ^ {
I' f public override void So rt() { . . . }
Da biste izbjegli ovo upozorenje moda ete htjeti svim svojim virtu-
alnim metodama dodati kljunu rije new. To nije dobra ideja. Kad se
kljuna rije new pojavi u kodu ona bi trebala dokumentirati inaice
koda. Ona potencijalnom klijentu pokazuje osnovnu klasu kako bi
vidio to ne premoujete. esto koritenje kljune rijei new podriva
takvu dokumentaciju. Nadalje, upozorenje postoji kako bi vam pomo-
glo da prepoznate stvarni problem.
Apstraktne klase
Svakapodklasa klase Control trebala bi implementirati vlastitu metodu DrawWindow()
-a li nita je na to ne obavezuje. Kako biste klase obavezali na implementaciju metode
^voje osnovne klase, trebate tu metodu oznaiti kao apstraktnu.
Apstraktna metoda nema implementaciju. Ona stvara naziv i potpis metode koji se
moraju implementirati u svim izvedenim klasama. Nadalje, oznaavanje jedne ili vie
metoda neke klase apstraktnima e i klasu uiniti apstraktnom.
Apstraktne klase tvore osnovu za izvedene klase, ali instancijacija objekta apstraktne
klase nije doputena. Deklariranjem apstraktne metode zabranjuje se stvaranje bilo
>kakvih instanci te klase.
J Stoga, ako DrawWindow() oznaite s abstract u klasi Control, moete izvoziti iz Control,
ali ne moete stvoriti objekte Control. Svaka izvedena klasa morala bi implementirati v
DrawWindow(). Ako izvedena klasa ne uspije implementirati apstraktnu metodu, klasa
Jjje isto bila apstraktna te instanciranje ponovno ne bi bilo mogue.
-^Metoda se s abstract oznaava tako da se kljuna rije abstract napie na poetku
spdefinicije metode:
r abstract public void DrawWindow();
Ako postoji jedna ili vie apstraktnih metoda, definicija klase se takoer mora oznaiti
- sabstract, kao u sljedeem primjeru:
abstract public class Control
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace abstractmethods
{
using System;
{
protected int top;
protected int left;
listBoxContents = contents;
}
110 | Programiranje C#
| fimjer5-2. Upotreba apstraktne metode i klase (nastavak)
, Console.WriteLine( "Mriting string to the listbox: {o}",
listBoxContents );
}
P
- - j g p p public class Button : Control
public Button(
int top,
int left ):
base(top, left)
{
}
// implementira apstraktnu metodu
}
}
* }
sa sljedeim kodom:
winArray[o] = new Control(l,2 );
Zapeaena klasa
U projektiranju programa, suprotno od apstraktnog je zapeaeno (engl. sealed). Iakol
je namjena apstraktne klase da se iz nje izvodi i da prui predloak koji trebaju slijediti!
njene podklase, zapeaena klasa uope ne doputa da se iz nje izvode klase. Ako sef
ispred deklaracije klase napie kljuna rije sealed, ona sprjeava izvoenje. Klase sef
sa sealed najee oznaavaju kako bi se sprijeilo sluajno nasljeivanje.
a\
r** Napomena za Java programere: zapeaena klasa u C # odgovara final-
V.N 4 noi k*as' uJavalezku.
Ako se deklaracija klase Control u primjeru 5-2 promjeni iz abstract u sealed (i elitni-'
nira kljuna rije abstract iz deklaracije DrawWindow()), program se nee prevesti. Ako|
pokuate izgraditi ovaj projekt, prevoditelj e vratiti sljedeu poruku o pogreci:
112 | Programiranje C#
,, 'LiitB::x' cannot inherit from sealed class 'Control'
^Olovna klasa je neposredan roditelj" izvedenoj klasi. Izvedena klasa moe biti
; osnova daljnjim izvedenim klasama stvarajui tako stablo" nasljeivanja ili hijerar-
^hl|U. Korijenska klasa je najvia klasa u hijerarhiji nasljeivanja. Korijenska klasa u
ob3ect- Nomenklatura je pomalo zbunjujua dok ne zamislite stablo okrenuto
'^naopako, s korijenom na vrhu i izvedenim klasama ispod njega. Osnovna klasa je
11ffakle, iznad" izvedene klase.
, Object prua razne virtualne metode koje podklase mogu premoivati. Meu njima je
^lEgualsO s kojom se utvruje jesu li dva objekta ista, GetType() koja vraa tip objekta
. (detaljnije je objanjena u poglavlju 8) i ToString() koja vraa niz za predstavljanje
p l i e g objekta (objanjeno u poglavlju 10). U tablici 5-1 moete pronai saetak
|metoaa klase Object.
using System;
using Sy st em . C ollecti ons.Ge neric;
using Sy stem.Text;
#endregion
pu b l i c class Tester
{
Console.WriteLine(
"The value of the object passed in is {0} , o.ToStringO );
To je javna virtualna metoda koja vraa niz i ne uzima parametre. Svi ugraeni tipovi,
poput tipa in t, izvedeni su iz Object i stoga mogu pozivati njene metode.
114 | Programiranje C#
fi^ er 5-3 premouje virtualnu metodu za SomeClass, to je uobiajen sluaj, tako da
metoda ToStringO moe vratiti smislenu vrijednost. Ako smjestite u komentar
iena
S noenu metodu, bit e pozvana osnovna metoda koja e izlaz promijeniti u:
The value of s is SomeClass
123
inti= 123 ;
123
object o=i;
}
}
Console.WriteLine() oekuje objekt, a ne cjelobrojnu vrijednost. Kako bi zadovo-
ljila metodu, CLR automatski pakira tip cjelobrojne vrijednosti, a na rezultirajuem
objektu se poziva ToString(). Ova znaajka omoguava stvaranje metoda koje kao
parametar uzimaju objekt. Metoda e funkcionirati bez obzira na to to joj se prosli-
jedi (referenca ili vrijednosni tip).
Na stogu Na gomili
inti= 123;
object o=i;
int j(int) o;
using System;
using System.Collections.Generic;
using System.Text;
116 | Programiranje C#
p r i m j e r 5 - 4 . P a k ir a n je i r a s p a k i r a v a n j e ( n a s t a v a k )
:#endregion
namespace boxing
//pakiranje
object o = i;
Ugnjeivanje klasa
Klase imaju lanove, a lan klase moe biti drugi korisniki definiran tip. Klasa Button,
dakle, moe imati lana tipa Location, a klasa Location moe sadravati lanove tipa
Point. Naposljetku, Point moe sadravati lanove tipa int.
Sadrana klasa ponekad moe postojati samo kako bi sluila vanjskoj klasi i ne mora
postojati razlog da bude vidljiva (ukratko, sadrana klasa slui kao pomona klasa).
Pomonu klasu moete definirati unutar definicije vanjske klase. Sadrana klasa se
naziva ugnijeena klasa (engl. nested class), a klasa koja ju sadri se jednostavno zove
vanjska klasa.
Ugnijeene klase mogu pristupati svim lanovima vanjske klase. Meotda ugnijeene
klase moe pristupiti privatnim lanovima vanjske klase.
Ugnijeena klasa moe biti skrivena od svih ostalih klasa - to jest, ona
moe biti privatna za vanjsku klasu.
U primjeru 5-5 prikazana je klasa Fraction A rtist koja je ugnijeena u klasi Fraction.
Metoda klase FunctionArtist je prikaz razlomka na konzoli. U ovom primjeru prikazi-
vanje izvodi par jednostavnih iskaza WriteLine().
P r im je r 5 - 5 . U p o t r e b a u g n i j e e n e k l a s e
using System;
using System.Collections.Generic;
using System.Text;
ttendregion
namespace NestedClasses
{
public class Fraction
{
private int numerator;
private int denominator;
118 | Programiranje C#
Primjer 5-5. U p o t r eb a u g n i je e n e k l a s e ( n a s t a v a k )
U Main() moete primijetiti kako za deklariranje instance ove ugnijeene klase morate
zadati naziv tipa vanjske klase:
Fraction.FractionArtist fa = new Fraction.FractionArtist();
Iako e ovaj iskaz funkcionirati, on je nespretan i to nije nain na koji se koriste ugra-
eni tipovi. Mnogo bi bolje bilo napisati:
Fraction theSum = firstFraction + secondFraction;
Ja za parametre obino koristim nazive lhs i rhs. Naziv lhs znai lijeva strana (engl. left
handside) i podsjea me da prvi parametar predstavlja lijevu stranu operacije. U skladu
s tim, rhs znai desna strana (engl. right hand side).
120
Sintaksa je z ik a C# za p re o p te reiv a n je o p e ra to ra je da se ispred op erato ra k o ji se
treba p reop teretiti n a p ie rije o p era to r. K lju n a rije op era to r je m o d ifika to r m eto de.
Stoga, za p re o p tereiv a n je op eratora zbrajan ja (+) treb ate n ap isati operator+.
poziva se preoptereeni operator +, pri emu se fir s t F ra c t io n prosljeuje kao prvi argu-
ment, a secon d Fraction kao drugi argument. Kada prevoditelj vidi izraz:
firstFraction + secondFraction
on ga prevodi u:
Fraction.operator+(firstFraction, secondFraction)
Stoga, ako preoptereujete operator zbrajanja (+), dobro bi bilo dodati i metodu add()
koja ima istu funkciju. Preoptereivanje operatora treba biti sintaktiki preac, a ne
jedini nain na koji objekti izvode odreeni zadatak.
Operator jednakosti
A ko p re o p te re u je te o p era to r je d n a k o s ti (==), p re p o ru ljiv o je p re m o stiti i virtualnu j j
m eto du E q u a ls() koju p ru a o b je c t i n je n u fu n k c io n a ln o st u sm je riti n a z a d do opera- |
tora je d n a k o s ti. T o k la si o m o g u a v a p o lim o rfn o st i k o m p a tib iln o s t s o sta lim .NET 1
je z icim a k o ji ne p re o p te re u ju o p e ra to re (ali p o d r a v a ju p re o p te re iv a n je metoda). F |
C L k la se n e e k o ris titi p re o p te re e n e o p era to re , ali e o e k iv a ti da k la se implemen- q
tira ju tem e ljn e m eto d e. K la sa o b je c t im p le m e n tira m e to d u E q u a ls () sa sljedeim |
p o tp iso m : 1
public Virtual bool Equals(object o)
i-f ( ! (o is Fractio n ) )
{
return false;
retu rn t h is == (F ra ctio n ) o;
}
O p e ra to r i s k o risti se k a k o bi se p ro v je rilo je li tip o b je k ta tije k o m iz v o en ja kompati-
b ila n s o p e ra n d o m (u o v om s lu a ju , s F r a c tio n ). Sto ga e o i s F ra c tio n b iti tru e ako
je o u stv a ri tip k o ji je k o m p a tib ila n s F r a c tio n .
122 | P ro g ra m ira n je C#
Operatori pretvaranja
C# int implicitno pretvara u long i omoguava eksplicitnu pretvorbu long u int. Pre-
' tvaranje int u long je implicitno (za njeno izvoenje nije potrebna nikakva sintaksa) i
| jj sigurno jer znate da e bilo koji int stati u memorijsku reprezentaciju long. Obrnuta
^ operacija, pretvaranje iz long u int mora biti eksplicitno (koritenjem operatora pretva-
> ranja tipa) jer se pri takvom pretvaranju mogu izgubiti informacije:
-** int mylnt = 5;
long myLong;
myLong = mylnt; // implicitno
mylnt = (int) myLong; // eksplicitno
return !(lhs==rhs);
}
public override bool Equals(object o)
124 | Programiranje C#
^ }^ p ritjtjer 6-1. Definiranje pretvorbi i operatora za operatore iz klase razlomaka (nastavak)
if (lhs.denominator == rhs.denominator)
{
return new Fraction(lhs.numerator+rhs.numerator,
lhs.denominator);
}
' Fraction f3 = fl + f 2 ;
Console.WriteLine("fl + f2 = f3: {o}", f3.ToStringO);
Fraction f4 = f3 + 5 ;
Klasa Fraction poinje s dva konstruktora. Jedan ima brojnik i nazivnik, a drugi cijeli
broj. Iza konstruktora slijedi deklaracija dva operatora pretvaranja. Prvi operator cje-
rojnu vrijednost mijenja u Fraction:
126 | Programiranje C#
. kod lake razumjeti s pomou primjera. Ako zbrajate 1 / 2 i 3/4, moete prvi
p j e)
l
fjngiik (l) pomnoiti drugim nazivnikom (4) i rezultat spremiti u firstProduct. Moete
ikbrojnik (3) pomnoiti prvim nazivnikom (2 ) i rezultat spremiti u secontProduct.
rugi
ve rezultate zbrojite (6+4), pri emu dobijete zbroj 1 0 , to je brojnik rezultata. Zatim
%noite dva nazivnika (2*4) kako biste generirali novi nazivnik (8 ). Toan odgovor
c razk>mak 1 0 /8 .
JgBnano, premostite ToStringO kako bi Fraction mogao svoju vrijednost vratiti u
"^.iJt>ku numerator/denominator:
,, V publlc override string T o StringO
^Sljedei red u Main() poziva statiki operator+. Svrha ovog operatora je zbrajanje dva
ikr^zlomka i vraanje zbroja u obliku novog razlomka:
Fraction f3 = fl + f2;
Console.UriteLine("f 1 + f2 = f3: { 0 } " , f3.ToStringO);
^Pozivae operatori, zatim konstruktor za f 3 koji uzima dvije int vrijednosti koje pred-
stavljaju brojnik i nazivnik rezultirajueg razlomka.
''Nova provjera u Main() zbraja int i Fraction f 3 i rezultirajuu vrijednost dodaje novom
razlomku f 4 :
1 Ponovimo jo jednom: 1/24/8, 3/4-6/8, 4/8+6/8=10/8. U primjeru razlomak nije skraen kako bi kod
> ostao to jednostavniji.
128 j Programiranje C#
POGLAVLJE 7
Strukture
Struktura (engl. struct) je jednostavan korisniki definiran tip, laka alternativa klasi.
Strukture su sline klasama u toliko to mogu sadrati konstruktore, svojstva, metode,
.f^polja, operatore, ugnijeene tipove i indekse (pogledajte poglavlje 9).
, Postoje i znaajne razlike izmeu klasa i struktura. Na primjer, strukture ne podravaju
ifnasljeivanje niti destruktore. to je jo vanije, iako je klasa referentni tip, struktura je
^'Vrijednosni tip (vie informacija o klasama i tipovima potraite u poglavlju 3). Strukture
Jflti stoga korisne za predstavljanje objekata koji ne zahtijevaju semantiku referenci.
f Opeprihvaeno stajalite je da se strukture trebaju koristiti samo za tipove koji su
jmali, jednostavni i po ponaanju i karakteristikama slini ugraenim tipovima.
Definiranje struktura
jffjntaksa za deklariranje strukture gotovo je identina onoj za definiranje klase:
[atributi] [modifikator pristupa] struct identifikator [:popis suelja]
{ lanovi }
129
U primjeru
menzionah
to bi se di
primijetiti
ih lanova-----
svojstva.
P r im je r 7-1. S t v a r a n je s t r u k t u r e
using System;
using S y s t e m . C o l le ct io ns . G en eri c ;
using System.Text;
(fendregion
{
public struct Location
xVal = xCoordinate;
yVal = yCoord inat e;
public int x
{
get
{
return xVal;
}
set
{
xVal = value;
}
}
public int y
1
. get
{
return yVal;
}
set
{
yVal = value;
}
130 ( Programiranje C#
'prim jer 7-1. S t v a r a n je s t r u k t u r e ( n a s ta v a k )
Stvaranje struktura
Instancu strukture moete stvoriti koristei kljunu rije new u iskazu dodjeljivanja,
isto kao da se radi o klasi. U primjeru 7-1 klasa Tester stvara instancu Location na
sljedei nain:
Location locl = new Location(200,300);
Ovdje je nova instanca nazvana lo cl i prosljeuju joj se dvije vrijednosti, 200 i 300.
WriteLine() oekuje objekt, ali, naravno, Location je struktura (vrijednosni tip). Pre-
voditelj automatski pakira strukturu (kao sto bi to uinio s bilo kojim drugim vrijed-
nosnim tipom) i taj se zapakirani objekt prosljeuje do W riteLine(). Za zapakirani
objekt poziva se ToStringO a kako struktura (implicitno) nasljeuje od object, ona
moe odgovoriti polimorfno, premoujui metodu na isti nain na koji bi to uinio
bilo koji drugi objekt:
Locl location: 200, 300
U ovoj knjizi termin objekt koristim i za referentne tipove i za vrijednosne tipove. U svijetu objektno ori- .
jentiranog programiranja postoji neslaganje oko takve prakse, ali ja se tjeim injenicom da je Microso
vrijednosne tipove implementirao kao da su naslijedili od korijenske klase Object (i stoga za bdo koji vri-
jednosni tip, ukljuujui ugraene cipove poput int, moete pozivati sve metode Object).
132 | Programiranje C#
Vl;i__ SU meutim, vrijednosni objekti i kad se prosljeuju do metode oni se pro-
jeuju po vrijednosti - kao to moete vidjeti u sljedeem redu koda u kojem se objekt
tici prosljeuje metodi myFunc():
t.myFunc(locl);
,Ovaj put objekt Location ima semantiku reference. Stoga, kad se vrijednosti promijene
mmyFunc(), one se promijene u stvarnom objektu u Main().-
Drugi nain za rjeavanje ovogproblema je upotreba kljune rijei ref (kao stoje objanjeno upoglavlju
v koja doputa da vrijednosni tip proslijedite po referenci.
using System;
using System.Collections.Oeneric;
using System.Text;
ftendregion
namespace StructWithoutNew
{
public struct Location
{
public int xVal;
public int yVal;
134 | Programiranje C#
7-2. S t v ara n je s t r u k t u r e b e z k l ju n e r i je i new ( n a s t a v a k )
ritnjer
{
Location locl; / / Nema poziva konstruktora
fa.- }
' }
, /}
H U primjeru 7-2 lokalne varijable se inicijaliziraju izravno prije pozivanja metode lo cl
j prije prosljeivanja objekta do WriteLine():
7$R, locl.xVal = 75;
4 r - iocl.yVal = 2 2 5 ;
Budite oprezni prilikom koritenja svojstava. Iako ona daju podrku za uahurivanje
tako to stvarne vrijednosti ine privatnima, sama su svojstva zapravo metode lanice,
a metodu lanicu ne moete pozvati dok ne inicijalizirate sve varijable lanice.
Suelje (engl. interface) je ugovor koji klijentu jam i kako e se klasa ili struktura
ponaati. Kad klasa (ili struktura) implementira suelje ona svakom potencijalnom
klijentu kae ja jam im da u podrati metode, svojstva, dogaaje i indekse ovog
suelja" (informacije o metodama i svojstvima potraite u poglavlju 4, informacije o
dogaajima u poglavlju 12, a vie o indeksima u poglavlju 9).
Suelje nudi alternativu apstraktnoj klasi za stvaranje ugovora izmeu klasa i njihovih I
klijenata. Ti se ugovori oituju koritenjem kljune rijei interface koja deklarira refe- 1
rentni tip koji uahuruje ugovor. j
Prilikom definiranja suelja moete definirati metode, svojstva, indeksere i/ili doga-
aje koje e implementirati klasa koja implementira suelje.
Suelja se esto usporeuju s apstraktnim klasama. Apstraktna klasa slui kao osnovna
klasa za obitelj izvedenih klasa, dok bi se suelja trebala mijeati s ostalim stablima
nasljeivanja.
Kad klasa implementira suelje, ona mora implementirati sve dijelove tog suelja
(metode, svojstva itd.). Klasa, u stvari, kae pristajem na ispunjavanje ugovora koji
je definiran ovim sueljem".
136
Mjeavine
USomerv*Neu<drava Massachusetts, postojala je nekad slastiarnica u kojoj bi vam
u omiljeni sladoled umijeali bombone i ostale slatkie. To se pionirima objektno
orijentiranog programiranja s oblinjeg sveuilita MIT koji su radili na programskom
jeziku SCOOPS inilo kao dobra metafora. Oni su termin mjeavina" primijenili i
na klase u koje su se mogle umijeati dodatne sposobnosti. C++ sadri brojne takve
klase. Takve klase imaju otprilike istu ulogu kao i suelja u C# .
-IvM-'
' \J ovom ete poglavlju nauiti kako se suelja stvaraju, implementiraju i koriste. Nau-
jit ete kako se implementiraju viestruka suelja, kako se suelja mogu kombinirati
"J d proiriti te kako se moe provjeriti je li klasa implementirala suelje.
i
Definiranje i implementiranje suelja
Sintaksa za definiranje suelja je sljedea:
[atributi] [modifikator pristupa] interface ime suelja[:popis osnovnih suelja]
{tijelo suelja}
< Iza kljune rijei interface navodi se naziv suelja. Uobiajeno je (ali ne i obavezno) da
fnaziv suelja poinje slovom I (dakle, IStorable, ICloneable, IClaudius itd.).
.. Popis osnovnih suelja daje popis svih suelja koje ovo suelje proiruje (kao to je
opisano u sljedeem odjeljku).
, Tijelo suelja opisuje metode, svojstva i druge elemente koje implementirajua klasa
^treba implementirati.
Pretpostavimo da elite stvoriti suelje koje opisuje metode i svojstva koja su klasi
^potrebna za spremanje i uzimanje podataka iz baze podataka ili drugog spremita, na
^primjer datoteke. To suelje odluili ste nazvati IStorable.
U ovom suelju moete zadati dvije metode: Read() i Write() koja se pojavljuju u tijelu
i suelja.
interface IStorable
{
void Read();
void Write(object);
P r im je r 8 - 1 . K o r i t e n j e j e d n o s t a v n o g s u e l ja
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace Simplelnterface
{
// Deklarira suelje
interface istorable
{
// Nema modifikatora pristupa, metode su javne
// Nema implementacije
void Read();
void Write( object obj );
int Status { get; set; }
138 | Programiranje C#
8-1 K o r i t e n je j e d n o s t a v n o g s u e l ja [n a s t a v a k )
Wf
1 console.WriteLine(
"Impleroenting the Read Method tor IStorable" );
}
// implementira metodu Write
public void Write( object o )
{
Console.WriteLine(
"Implementing the Write Method tor IStorable );
}
// Implementira svojstvo
public int Status
{
get
{
return status;
}
status = value;
}
'I I Koristi suelje
public class Tester
{
U primjeru 8-1 definirano je jednostavno suelje IStorable koje sadri dvije metode
(Read() i W rite()) i svojstvo (Status) tipa integer. Obratite panju da deklaracija svoj-
stva ne prua implementaciju za g et() i se t(), ve jednostavno oznaava kako postoje
get() i s e t():
int Status { get; set; }
Kad je to uinjeno, klasa Document mora implementirati i metode koje zadaje suelje
ICompressible (koje je deklarirano u primjeru 8-2):
}
public void Decompress()
Proirivanje suelja
Postojee suelje moe se proiriti kako bi se dodale nove metode ili lanovi, odnosno
kako bi se promijenio nain funkcioniranja postojeih lanova. ICompressible moete,
na primjer, proiriti novim sueljem ILoggedCompressible koje poetno suelje proi-
ruje metodama koje evidentiraju pohranjene bajtove.
interface ILoggedCompressible : ICompressible
void LogSavedBytes();
}
Ako ICom pressible proirite na ovaj n ain , zapravo n aznau jete da sve
on o to im plem entira ILoggedCompressible m ora im plem entirati i ICom-
p re ssib le .
140 | Programiranje C#
sada slobodno mogu implementirati ili ICompressible ili ILoggedCompressible,
ja e
|nbiniranje suelja
^ lino tome, nova suelja moete stvoriti kombiniranjem postojeih suelja i, opcio-
%ialno, dodajui nove metode ili svojstva. Na primjer, moete stvoriti IStorableCompres-
-;sible. To bi suelje kombiniralo metode oba suelja, ali bi dodalo i novu metodu za
^spremanje izvorne veliine unaprijed komprimirane stavke:
interface IStorableCompressible : IStorable, ILoggedCompressible
-i {
void LogOriginalSize();
; i
Prim jer 8 - 2 . P r o ir iv a n je i k o m b i n i r a n je s u e l ja
jising System;
using System.Collect ions.Generic;
using System.Text;
jfendregion
namespace ExtendAndCombineInterface
{
interface IStorable
f
void Read();
void Write( object obj );
int Status { get; set; }
U Proirenje suelja
interface ILoggedCompressible : ICompressible
void LogSavedBytes();
H Kombiniranje suelja
interface IStorableCompressible : IStorable, ILoggedCompressible
{
// Dri podatke za svojstvo Status suelja IStorable
private int status = o;
// Konstruktor dokumenta
public Document( string s )
}
// Implementacija IStorable
public void Read()
{
Console.WriteLine(
"Implementing the Read Method for IStorable" );
}
public void Write( object o )
{
Console.WriteLine(
"Implementing the Write Method for IStorable" );
}
public int Status
{
get
{
return status;
}
set
{
status = value;
}
}
// Implementacija ICompressible
public void Compress()
142 | Programiranje (#
J f r f n i j e r 8 - 2 . P r o ir iv a n je i k o m b in ir a n je suelja (nastavak)
}
5i> public void Decompress()
{
Console.WriteLine( "Implementing Decompress" );
}
// Implementiranje ILoggedCompressible
public void LogSavedBytes()
{
Console.WriteLine( "Implementing LogSavedBytes" );
}
// Implementiranje IStorableCompressible
public void LogOriginalSize()
{
Console.WriteLine( "Implementing LogOriginalSize" );
// Implementiranje IEncryptable
public void Encrypt()
{
Console.WriteLine( "Implementing Encrypt" );
}
}
}
else
Program Tester stvara novi objekt Document i zatim ga koristi kao instancu razliitih
suelja. Slobodno moete pretvarati:
ICompressible icDoc = doc as ICompressible;
144 | Programiranje C#
ICompressible icDoc = doc as ICompressible;
if ( icDoc \- nuli )
icDoc.Compress();
else
Console.WriteLine( "Compressible not supported" );
S
Pretvaranje u proirena suelja
^ Kad je objekt pretvoren u ILoggedCompressible moete koristiti suelje za pozvanje
metoda na ICompressible jer ILoggedCompressible proiruje (i stoga obuhvaa) metode
iz osnovnog suelja:
ILoggedCompressible ilcDoc = doc as ILoggedCompressible;
if (ilcDoc != nuli)
{
ilcDoc.LogSavedBytes();
ilcDoc.Compress();
// ilcDoc.Read();
}
Ne moete, meutim, pozvati Read() jer se radi o metodi suelja IStorable koje nije
povezano. Ako poziv metode Read() izdvojite u komentar, primit ete pogreku pre-
' voditelja.
? {
isc-LogOriginalSize(); // IStorableCompressible
isc.LogSavedBytes(); // ILoggedCompressible
isc.Compress(); // ICompressible
isc.Read(); // IStorable
>
Kao to je ranije navedeno, suelja se ne mogu izravno instancirati. T o jest, ne moete *i operatora i s iest:
napisati: ;; izraz is tip
IStorable isDoc = new IStorable(); Operator is ima vrijednost true ako se izraz (koji mora biti referentni tip) moe sigurno
Meutim, moete stvoriti instancu implementirajue klase, kao u sljedeem odlomku pretvoriti u tip bez izbacivanja iznimke.' U Primjeru 8-3 prikazana je upotreba opera-
koda: tora is za provjeru implementira li Document suelja IStorable i ICompressible.
namespace IsOperator
Pretvaranje u suelje ;<
r. interface IStorable
U veini sluajeva se ne zna unaprijed podrava li objekt neko suelje. U kolekciji {
dokumenata moda neete znati podrava li odreeni objekt suelje IStorable ili ICom- void Read();
void Write( object obj );
pressible ili oba. Moete samo pretvarati u suelja:
int Status { get; set; }
Document doc = myCollection[0];
146 | Programiranje C#
Poglavlje 8: Suelja | 147
P r im j e r 8 - 3 . K o r i t e n j e o p e r a t o r a is (n a s t a v a k )
// IStorable.Read
public void Read()
{
Console.WriteLine( "Reading..
}
// IStorable.Write
public void Write( object o )
{
Console.WriteLine( "Writing..
}
// IStorable.Status
public int Status
{
get
{
return status;
}
set
{
status = value;
}
}
}
// Izvodi iz Document i implementira ICompressible
public class CompressibleDocument : Document, ICompressible
{
public CompressibleDocument(String s) :
base(s)
{ }
public void Compress()
{
Console.WriteLine("Compressing..
}
public void Decompress()
{
Console.WriteLine("Decompressing...
}
148 | Programiranje C#
frimjer 8-3- Koritenje operatora is (nastavak)
}
public class Tester
{
i static void Main()
: {
// Kolekcija Documents
Document[] docArray = new Document[2];
// Ne uspjeva za Document
// Prolazi za CompressibleDocument
it (doc is ICompressible)
{
ICompressible icDoc = (ICompressible)doc;
icDoc.Compress();
}
}
* )
) Taj je postupak jasan i gotovo da sam sebe objanjava. Iskaz i f govori da e se pretva-
3. ranje dogoditi samo ako objekt pripada ispravnom tipu suelja.
Oba tipa dokumenta stavljamo u polje (moete zamisliti predavanje takvog polja
metodi koja ne moe znati kakav je sadraj polja). Prije nego to pokuate pozvati
metode iz ICompressible, morate biti sigurni da tip kojem pripada Document implemen-
tira ICompressible. To e umjesto vas provjeriti operator is.
Na alost, ovakva upotreba operatora is nije uinkovita. Kako biste razumjeli zato,
morate pogledati MSIL kod koji se generira. Evo malog odlomka (primijetit ete kako
su brojevi redaka u heksadecimalnom zapisu).
IL0023: isinst ICompressible
IL_0028: brfalse.s IL_0039
IL_002a: ldloc.o
IL_002b: castclass ICompressible
IL_0030: Stl0C.2
IL_003l: ldloc . 2
IL_0032: callvirt instance void ICompressible::Compress()
Operator as
Operator as kombinira operator is s operacijama pretvaranja tako to prvo provjerava
je li pretvaranje valjano (to jest, bi li provjera s is vratila true), a zatim, ako pretvaranje
jest valjano, zavrava pretvaranje. Ako pretvaranje nije valjano (to jest, ako provjera s
is vrati vrijednost false), operator as vraa vrijednost nuli.
ari
Kljuna rije nuli predstavlja praznu referencu - onu koja ne pokazuje
ni na jedan objekt.
i
Koritenje operatora as eliminira potrebu za obradom iznimki pretvaranja tipa. U isto
vrijeme izbjegavate i dvostruku provjeru pretvaranja. Iz tih je razloga za pretvaranje
tipa suelja najbolje koristiti operator as.
Kod iz primjera 8-3 je u sljedeem odlomku koda prilagoen tako da se koristi opera-
tor as i provjerava se hoe li povratna vrijednost biti nuli:
static void Main()
150 j Programiranje C#
// Kolekcija Documents
Document[] docArray = new Document[2 ];
// Ne prolazi za Document
// Prolazi za CompressibleDocument
ICompressible icDoc = doc as ICompressible;
if (icDoc != nuli)
{
icDoc.Compress();
}
}
}
'Ako pogledate odgovarajui MS1L kod, primijetit ete kako je ova inaica daleko
^uinkovitija:
IL_0023: isinst ICompressible
IL_0028: stloc.2
IL_0029: ldloc.2
IL_002a: brfalse.s IL_0034
IL_002c: ldloc.2
m .
:le*V
IL 002d: callvirt instance void ICompressible::Compress()
152 | Programiranje C#
premoivanje implementacija suelja
rjinplementirajua klasa moe neke, ili sve, metode koje implementiraju suelje slo-
b dn0 oznaiti kao virtualne. Izvedene klase mogu premostiti (override) te implemen-
;%||I|taCIJe kako bi postigle polimorfizam. Na primjer, klasa Document moe implementirati
^Jlfl'suelj IStorable i metode Read() i Write() oznaiti s Virtual. Document moe svoj
'Iflsadraj proitati (Read()) i zapisati (Write()) u tip File. Razvojni inenjer moe kasnije
izDocument izvoditi nove tipove, na primjer Note ili EmailMessage te moe odluiti kako
Jl'.e Note itati iz baze podataka ili zapisivati u nju, a ne u datoteku.
-
P rim jer 8 - 4 . P r e m o i v a n j e i m p l e m e n t a c i j e s u e l ja
. using System;
using System.Collections.Oeneric;
using System.Text;
#endregion
v-namespace overridinglnterface
interface IStorable
1
void Read();
void Write();
}
Console.WriteLine( "\n" );
154 | Programiranje C#
t*Primjer Premoivanje implementacije suelja (nastavak)
I I Pravi objekt Note
Note rote2 = new Note( "Second Test" );
IStorable isNote2 = note2 as IStorable;
if ( isNote2 != nuli )
{
isNote2.Read();
isNote2.Write();
}
Console.WriteLine( "\n" );
}
}
Uovom primjeru Document implementira pojednostavljeno suelje IStorable (pojedno-
stavljeno kako bi primjer bio to jasniji):
interface IStorable
{
void Read();
void Write();
Razvojni inenjer koji je stvorio Document je metodu Read() oznaio kao virtualnu, ali
to nije uinio s metodom W rite():
public Virtual void Read()
Note ne mora premostiti metodu Read(), no moe to slobodno uiniti, kao stoje sluaj
u primjeru:
public override void Read()
Zatim se metode Read() i W rite() pozivaju kroz to suelje. Izlaz otkriva kako se na
metodu Read() odgovara polimorfno, to, prema oekivanju, nije sluaj s metodom
W rite():
Overriding the Read pethod for Note!
Document Write Method for IStorable
156 | Programiranje C#
to e se dogoditi ako klasa implementira dva suelja i oba suelja sadre metodu
s istim potpisom? U primjeru 8-5 stvorena su dva suelja: IStorable i ITalk. Drugo
suelje implementira metodu Read() koja knjigu ita na glas. Ona se, na alost, suko-
bljava s metodom Read() iz suelja IStorable.
Metoda koja se deklarira putem eksplicitne implementacije se, u stvari, ne moe dekla-
rirati s modifikatorima abstract, Virtual, override i new.
P r im jer 8 - 5 . E k s p l ic it n a i m p l e m e n t a c i j a
using System;
using System.Collections.Generic;
using System.Text;
(fendregion
namespace ExplicitImplementation
interface ITalk
{
vo id Talk();
void Read();
}
// Modi fi ka ci ja Document da imple m entira ISto rable i ITalk
public class Do c ument : IS torable, ITalk
{
// Ko n strukt or do ku me nt a
public Document( string s )
}
// i ni Read() vi rt u a l n o m
public Virt ua l void Read()
}
public vo id Write()
}
void ITalk.Read()
}
public vo id Talk()
}
}
public class Tester
{
static vo id Main()
{
// Pr av i ob je k t d okumen ta
Document t heDoc = new Document( "Test Do cu me nt" );
158 | Programiranje C#
primjer 8-5. Eksplicitna implementacija (nastavak)
IStorable isDoc = theDoc;
isDoc.Read();
theDoc.Read();
theDoc.Talk();
}
}
Sakrivanje lana
lan suelja moe biti skriven. Pretpostavimo da elite da suelje IBase ima svojstvo P;
interface IBase
{
int P { get; set; }
}
Pretpostavimo i da iz tog suelja izvodite novo suelje IDerived koje svojstvo P skriva
novom metodom P():
160 | Programiranje C#
'fim jer 8 - 6 . R e f e r e n c e n a v r i je d n o s n e t ip o v e
b'sing System;
. #endregion
pamespace ReferencesOnValueTypes
{
7 / Deklarira jednostavno suelje
intertace IStorable
{
void Read();
int Status { get;set;}
Poglavlje 8
Primjer 8-6. Reference na vrijednosne tipove (nastavak)
Console.WriteLine(
theStmct.Status: {0}", theStruct.Status );
// Mijenja vrijednost
theStruct.Status = 2;
Console.WriteLine( "Changed object. );
Console.WriteLine(
"theStruct.Status: {o}", theStruct.Status );
Zanimljiv se kod nalazi unutar Tester. Poinje stvaranjem instance strukture i inicija-
liziranjem njenog svojstva na -1. Vrijednost statusa se zatim ispisuje:
myStruct theStruct = new myStruct();
theStruct.status = -l; // Inicijaliziranje
Console.WriteLine(
"theStruct.Status: {0}", theStruct.status);
Zatim se pristupa svojstvu radi promjene statusa, ponovno putem samog objekta vri-
jednosti;
// Mijenja vrijednost
theStruct.status = 2;
Console.WriteLine("Changed object.");
Console.WriteLine(
"theStruct.Status: {0}", theStruct.status);
162 | Programiranje C#
^ 'Promjena se moe vidjeti u izlazu:
Changed object.
theStruct.Status: 2
po sad se nije dogodilo nita neobino. Sada se stvara referenca do suelja IStorable.
To e uzrokovati implicitno pakiranje objekta vrijednosti theStruct. Zatim se suelje
koristi za promjenu vrijednosti statusa na 4:
// Pretvara tip u IStorable
// implicitno pakira u referentni tip
IStorable isTemp = ( IStorable ) theStruct;
Ako pogledamo MSIL kod (primjer 8-7) otkrit emo to se zapravo dogaa u pozadini.
entrypoint
// Code sie 1 9 4 (0 xc 2 )
.maxstack 3
locals init ([0 ] valuetype ReferencesOnValueTypes.myStruct theStruct,
[1 ] class ReferencesOnValueTypes.IStorable isTemp)
IL_0 0 0 0 : ldloca.s theStruct
IL_0 0 0 2 : initobj ReferencesOnValueTypes.myStruct
IL_0 0 0 8 : ldloca.s theStruct
IL_0 0 0 a: ldc.i4 .ml
ILo oo b: call instance void ReferencesOnValueTypes.myStruct::set_Status(int3 2 )
IL_0 0 2 6 : nop
IL OO2 7 : ldloca.s theStruct
IL 0029: ldc.i4.2
IL 002a: call instance void ReferencesOnValueTypes.myStruct::set_Status(int32)
IL~002f: ldstr "Changed object."
IL 0034: call void [mscorlib]System.Console::WriteLine(string)
IL_0039: nop
IL_003a: ldstr "theStruct.Status: {0}"
IL 003f: ldloca.s theStruct
IL 0041: call instance int32 ReferencesOnValueTypes.myStruct::get_Status()
IL 0046: box [mscorlib]System.Int32
IL_004b- call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0050: nop
IL_0051: ldloc.O
IL_0052: box ReferencesOnValueTypes.myStruct
IL_0057: stloc.l
IL_0058: ldloc.l
IL 00 59 : ldc.i4.4
IL_008b: nop
IL_008c: ldloca.s theStruct
IL_0 0 8 e: ldc.i4.6
instance void ReferencesOnValueTypes.myStruct::set_Status(int32)
IL_008f: call
IL_0094: ldstr "Changed object."
164 | Programiranje C#
Jprimjer 8-7. MSIL kod za primjer 8-6 (nastavak)
3*
!
.N ET kostur prua mnotvo klasa kolekcija. Od pojave generika u inaici 2.0 veina
ovih klasa kolekcija sada su sigurne za tipove, ime je samo programiranje uvelike
olakano. U te se klase ubrajaju Array, List, Dictionary, Sorted Dictionary, Oueue i
Stack.
Najjednostavnija kolekcija jest Array, jedini tip kolekcije za koju C # prua ugraenu
podrku. U ovom poglavlju ete nauiti kako se radi s jednostrukim, viedimenzio-
nalnim i nejednakim poljima. Polja imaju ugraene indeksere, to vam omoguava da
zatraite n-ti lan polja. U ovom je poglavlju objanjeno i stvaranje vlastitog indeksera
to vam omoguava da svojstvima klase pristupite kao da je klasa indeksirana poput
polja.
.NET kostur prua razna suelja, poput IEnumerable i ICollection ija vam implemen-
tacija omoguava standardne naine interakcije s kolekcijama. U ovom ete poglavlju
vidjeti kako se radi s najosnovnijim. Poglavlje zavrava pregledom .N ET kolekcija koje
se najee koriste, a u koje se ubrajaju L ist, Dictionary, Oueue i Stack.
Polja
Polje (engl. array) je indeksirana kolekcija objekata koji su svi istog tipa. Polja u jeziku
C # se pomalo razlikuju od polja u C++ jer su objekti. To im prua razne korisne
metode i svojstva.
166
?# prua izvornu sintaksu za deklariranje polja. Ono to se zapravo stvara jest objekt
ijpa System.Array. Polja jezika C # stoga vam pruaju najbolje od oba svijeta: jedno-
tavnu sintaksu u C stilu koju podupire stvarna definicija klase tako da instance polja
jrriaju pristup metodama i svojstvima iz System.Array. Te su metode i svojstva opisani
utablici 9-1.
Tablicu 9 -1 . M e t o d e i s v o js t v a S y s t e m .A r r a y
gttodailisvojstvo Svrha
BinaiySearch() Preoptereena javna statika metoda koja trai jednodimenzionalno sortirano polje.
Clear() Javna statika metoda koja raspon elemenata u polju postavlja na 0 ili na referencu nuli.
Copy() Preoptereena javna statika metoda koja dio jednog polja kopira u drugo polje.
Createlnstance() Preoptereena javna statika metoda koja stvara novu instancu polja.
IndexOf() Preoptereena javna statika metoda koja vraa indeks (pomak) prve instance vrijednosti
ujednodimenzionalnom polju.
Last IrdexOff () Preoptereena javna statika metoda koja vraa indeks posljednje instance vrijednosti
u jednodimenzionalnom polju.
Reverse() Preoptereena javna statika metoda koja elemente jednodimenzionalnog polja postavlja
u obrnuti redoslijed.
Sort() Preoptereena javna statika metoda koja sortira vrijednosti u jednodimenzionalnom polju.
SyncRoot Javno svojstvo koje vraa objekt koji se moe koristiti za sinkronizaciju pristupa polju.
GetEnumerator() Javna metoda koja vraa IE n u m e ra to r.
v CetLength() Javna metoda koja vraa duljinu zadane dimenzije polja.
GetLowerBound() Javna metoda koja vraa donju granicu zadane dimenzije polja.
GetUpperBound() Javna metoda koja vraa gornju granicu zadane dimenzije polja.
Initialize() Inicijalizira sve vrijednosti u polju vrijednosnog tipa pozivanjem podrazumijevanog konstruktora
za svaku vrijednost. U referentnim poljima svi su elementi postavljeni na nuli.
SetValue() Preoptereena javna metoda koja zadane elemente polja postavlja na neku vrijednost.
Naravno, prilikom stvaranja polja s pomou in t [] myArray - new in t[s] u I L kodu zapravo stvarate
instancu System.int32[ ], no budui da izvodi iz apstraktne osnovne klase System.Array, moe se rei i da
ste stvorili instancu System.Array.
4
Zapravo se ne deklarira polje. Tehniki deklarirate varijablu (myIntAr- j
ray) koja e sadrati referencu polja cjelobrojnih vrijednosti. Kao i j
obino, koristit emo preac i myIntArray nazivati poljem, znajui da se
' zapravo radi o varijabli koja sadri referencu (neimenovanog) polja.
Uglate zagrade ([]) C # prevoditelju govore da se radi o deklaraciji polja, a tip odreuje ;
tip elemenata koje e polje sadrati. U prethodnom primjeru myIntArray je polje cjelo- :
brojnih vrijednosti.
Instancirajte polje koristei kljunu rije new. Na primjer:
myIntArray = new int[5];
Ovom se deklaracijom stvara i inicijalizira polje od pet cjelobrojnih vrijednosti koje su
sve inicijalizirane na vrijednost 0.
168 | Programiranje C#
Razum ijevanje podrazumijevanih vrijednosti
IfeijCada stvorite polje vrijednosnih tipova, svaki element na poetku sadri podrazumij e-
' vanu vrijednost za tip spremljen u polju (pogledajte tablicu 4-2). Iskaz:
myIntArray = new i n t [ 5 ] ;
* 4 Pretpostavimo kako ste stvorili klasu Button. Deklarirajte polje Button objekata slje-
^.deim iskazom:
Button[] myButtonArray;
. , Ovim se iskazom ne stvara polje s referencama tri Button objekata. Umjesto toga se
stvara polje myButtonArray s tri reference nuli. Za koritenje ovog polja prvo morate
konstruirati i dodijeliti Button objekte svakoj referenci u polju. Objekte moete kon-
struirati u petlji koja ih jedan po jedan dodaje u polje.
. i Kao to je ranije objanjeno, polja su objekti i stoga imaju svojstva. Jedno od korisni-
ji jih svojstava je Length koje govori koliko elemenata polje sadri. Objekti polja mogu
se indeksirati od 0 do Length-l. To jest, ako u polju postoji pet elemenata, njihovi su
indeksi 0 ,1 , 2, 3, 4.
: Dosad opisani koncepti polja prikazani su u primjeru 9-1. U ovom primjeru klasa
Testei stvara polje Employees i polje cjelobrojnih vrijednosti, ispunjava polje Employee
: i zatim ispisuje vrijednosti oba polja.
// Ispunjava polje
for (int i = 0;i<empArray.Length;i++)
{
empArray[i] = new Employee(i+5);
}
170 | Programiranje C#
Iskaz foreach
Iskaz petlje foreach nov je u obitelji C jezika, iako je ve dobro poznat VB programe
rima. On omoguava iteraciju kroz elemente polja ili druge kolekcije, pri emu se svaki
element provjerava. Sintaksa iskaza foreach je sljedea:
foreach (tip identifikator in izraz) iskaz
Primjer 9-1 stoga moete aurirati i iskaze for koji iteriraju kroz sadraj ispunjenih
polja zamijeniti iskazima foreach, kao stoje prikazano u primjeru 9-2
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace UsingForEach
{
// Jednostavna klasa koja e pohranjivati u polje
public class Employee
{
// Jednostavna klasa koja e pohranjivati u polje
public Employee( int empID )
this.empI = empID;
}
public override string ToStringO
r e t u r n em p ID .ToStringO;
// Ispunjava polje
for ( int i = 0 ; i < empArray.Length; i++ )
Console.WriteLine( i.ToStringO );
}
foreach ( Employee e in empArray )
{
Console.WriteLine( e.To Strin g O );
}
}
}
}
}
Izlaz primjera 9-2 identian je onom iz primjera 9-1. Meutim, umjesto stvaranja
iskaza for koji mjeri veliinu polja i kao indeks koristi privremenu varijablu za broja-
nje, pokuali smo s drugim pristupom:
for (int i = 0; i < empArray.Length; i++)
{
Console.WriteLine(empArray[i] .ToString());
}
Iteracija kroz polje se izvodi s pomou petlje foreach koja automatski iz polja izdvaja slje-
dei element i dodjeljuje ga privremenom objektu koji je stvoren u zaglavlju iskaza:
foreach (Employee e in empArray)
{
Console. UriteLine (e.ToStringO);
}
Objekt koji je izdvojen iz polja pripada odgovarajuem pa za njega moete pozvati bilo
koju javna metodu.
Nema funkcionalne razlike izmeu ova dva iskaza i veina e programera koristiti
krau sintaksu, no pogledajte sljedeu napomenu.
a 4
Dvije sintakse postoje jer se u nekim situacijam a mora koristiti dua
sintaksa - na primjer, ako C # prevoditelj ne moe zakljuiti ispravan
!*,' tip polja.
172 | Programiranje C#
Sljedeem se primjeru stvara metoda DisplayVals() koja uzima promjenjiv broj cje-
Ri$jjjbrojnih argumenata.
public void DisplayVals(params int[] intVals)
ST
,;
foreach (int i in intVals)
{
Console.WriteLine("DisplayVals {0}",i);
}
^Pozivajua metoda, meutim, ne mora eksplicitno stvoriti polje. Ona jednostavno
vimoe proslijediti cjelobrojne vrijednosti i prevoditelj e parametre sakupiti u polje za
f^jpetodu DisplayVals():
X' t.DisplayVals(5,6,7,8);
U primjeru 9-3 naveden je cjelokupan izvorni kod koji prikazuje upotrebu kljune
rijei params.
i;using System;
using System.Collections.Generic;
using System.Text;
>#endregion
narespace UsingParams
#{
public class Tester
{
static void Main()
{
Tester t = new Tester();
t.DisplayVals(5,6,7,8);
int [] explicitArray = new int[5] {1,2,3,4,5};
t.DisplayVals(explicitArray);
}
public void DisplayVals(params int[] intVals)
{
foreach (int i in intVals)
{
Console.WriteLine(DisplayVals {0}",i);
}
}
1
}
itatelji koji nisu fiziari do sad su vjerojatno odustali, ba kao i ja. Viedimenzio-
nalna polja su, meutim, korisna ak i ako ne moete zamisliti kako bi ona trebala
izgledati.
C# podrava dva tipa viedimenzionalnih polja: pravokutna (engl. rectangular) i nejed-
naka (engl. jagged). U pravokutnom polju svaki je red iste duljine. Nejednaka se polja
sastoje od polja, a svako polje moe biti razliite duljine.
Pravokutna polja
Pravokutno polje ima dvije (ili vie) dimenzije. Prva dimenzija klasinog dvodimenzio-
nalnog polja je broj redova, a druga je broj stupaca.
P r im je r 9 - 4 . P r a v o k u t n o p o l j e
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace RectangularArray
{
174 | Programiranje C#
p rim jer 9-1. P r a v o k u t n o p o l j e ( n a s t a v a k )
{
static void Main()
// Ispunjava polje
for ( int i = 0 ; i < rows; i++ )
{
for ( int j = o; j < columns; j++ )
{
rectangularArray[i, j] = i + j;
}
}
// Ispisuje sadraj polja
for ( int i = o; i < rows; i++ )
{
for ( int j = 0; j < columns; j++ )
{
Console.WriteLine( "rectangularArray[{o},{l}] = {2},
i, j, rectangularArray[i, j] );
}
}
}
}
}
U ovom se primjeru deklarira par konstantnih vrijednosti:
const int rows = 4;
codst int columns = 3;
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace InitializingMultiDimensionalArray
{
public class Tester
{
static void Main()
{
const int rows = 4;
const int columns = 3 ;
176 | Programiranje C#
i biste polje dimenzija 3x4.
Iete uoiti da C# prevoditelj razumije vae naznake jer moe pristupiti objektima
%govarajuim pomacima, kao to se vidi u izlazu.
o?da ete pomisliti kako, budui da se radi o polju od 12 elemenata, jednako lako
blete pristupiti elementu na rectangularArray[0,3] (etvrtom elementu u prvom
;|u) kao ionom na rectangularArray[l,0] (prvomelementu udrugom redu). To funk-
||nira u C++, ali ako to pokuate u C# , generirat e se sljedea iznimka:
5 j Exception occurred: System.IndexOutOfRangeException:
W f : Index was outside the bounds of the array.
at programming_CSharp.Tester.Main() in
cshaip\programming csharp\listing0703.cs:line 23
-Silolja ujeziku C # su pametna i paze na svoja ogranienja. Ako naznaite polje dimen-
x@ ] a 4*3, morate ga i tretirati kao takvo.
^Nejednaka polja
Nejednako polje (engl. jagged array) je polje sastavljeno od polja. Naziva se nejednako"
jjer ne moraju svi redovi biti iste veliine pa grafiki prikaz polja ne bi bio kvadratan.
iprilikom stvaranja nejednakog polja deklarirate broj redova u polju. Svaki e red sadr-
' sati polje koje moe biti bilo koje duljine. Svako se od ovih polja mora zasebno dekla-
mirati. Zatim moete ispuniti vrijednosti elemenata u tim unutarnjim" poljima.
Svaku dimenziju nejednakog polja ini jednodimenzionalno polje. Za deklariranje
mfeednakog polja koristite sljedeu sintaksu u kojoj broj zagrada zadaje broj dimen-
z i j a polja:
tip [] []...
;jendregion
178 | Programiranje C#
9 -6 . R ads nejednakim poljima (nastavak)
Console.WriteLine( "jaggedArray[3][{0}] = {1}",
i, jaggedArray[3][i] );
}
' Moete primijetiti kako druga dimenzija nije zadana. To je odreeno stvaranjem novog
polja za svaki red. Svako polje moe biti razliite veliine:
// Prvi red ima pet elemenata
jaggedArray[o] = new int[5];
Kad je polje zadano za svaki red trebate samo popuniti razliite lanove svakog polja
i zatim ispisati njihov sadraj kako biste provjerili je li sve u redu.
Obratite pozornost da, kada pristupate lanovima pravokutnog polja, svi se indeksi
stavljaju unutar jednog skupa uglatih zagrada:
rectangularArrayrectangularArray[i,j]
Prvu varijantu moete shvatiti kao jedno polje s vie dimenzija, a drugu kao polje
sastavljeno od polja.
Granice polja
Klasa Array moe se stvoriti i s pomou preoptereene metode Createlnstance. Jedno
od preoptereenja omoguava zadavanje donje granice (poetnog indeksa) svake
dimenzije viedimenzionalnog polja. Ova je mogunost prilino nejasna i ne koristi
se esto.
Ukratko, evo kako to moete uiniti: pozovete statiku metodu Createlnstance koja
vraa Array i prihvaa tri parametra: objekt tipa Type (oznaava tip objekata koji e
se nalaziti u polju), polje cjelobrojnih vrijednosti koje oznaava veliinu svake dimen-
zije u polju i drugo polje cjelobrojnih vrijednosti koje oznaava donju granicu svake
dimenzije. Dva polja cjelobrojnih vrijednosti moraju imati isti broj elemenata tj. za
svaku dimenziju morate zadati donju granicu:
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace SettingArrayBounds
{
Pretvaranje polja
Polja se mogu meusobno pretvarati ako su njihove dimenzije jednake i ako je mogue
pretvaranje izmeu tipova elemenata. Implicitna se pretvorba moe provesti ako se ele-
menti mogu implicitno pretvarati; u suprotnom pretvaranje mora biti eksplicitno.
Polje izvedenih objekata se, naravno, moe pretvoriti u polje osnovnih objekata. U
primjeru 9-7 prikazana je pretvorba polja korisniki definiranih tipova Employee u
polje objekata.
180 | Programiranje C#
primjer 9-7. Pretvaranje polja
Ijegion Using directives
using System;
using System.Collections.Ceneric;
using System.Text;
(fendregion
namespace ConvertingArrays
{
myEmployeeArray[i] = new Employee( i + 5 );
}
// Prikazuje vrijednosti
PrintArray( myEmployeeArray );
PrintArray() zatim poziva metodu ToStringO za svaki element polja koji uzima kao
parametar. Budui da je ToStringO virtualna metoda u osnovnoj klasi Object, ona e
sigurno biti dostupna u svakoj izvedenoj klasi. Tu ste metodu preopteretili u Employee
te kod ispravno funkcionira. Pozivanje metode ToStringO za objekt String moda nije
potrebno, ali ne moe biti tetno i omoguava vam polimorfno tretiranje tih objekata.
Sortiranje polja
U Array postoje dvije korisne metode Sort() i Reversef). One su potpuno podrane za
polja ugraenih C # tipova poput String. Primjena tih metoda na klase koje ste sami
stvorili neto je kompliciranija jer morate implementirati suelje IComparable (pogle-
dajte odjeljak Implementacija suelja IComparable1' u nastavku ovog poglavlja). U
primjeru 9-8 prikazana je upotreba te dvije metode za rad s objektima String.
182 | Programiranje C#
ii primjer 9-8. Koritenje metoda Array.Sort i Array.Reverse
1 ffregion Using directives
using System;
using System.Collections.Generic;
using System.Text;
Oendregion
namespace ArraySortAndReverse
{
public class Tester
{
public static void PrintMyArray( objectf] theArray )
Consoie.UriteLine( "\n" );
PrintMyArray( myArray ) ;
Array.Reverse( myArray );
PrintMyArray( myArray );
String[] myOtherArray =
PrintMyArray( myOtherArray );
Array.Sort( myOtherArray );
PrintMyArray( myOtherArray );
}
}
Na slian nain primjer stvara drugo polje myOtherArray koje sadri sljedee rijei:
"We", "Hold", "These", "Truths",
"To", "Be", "Self", "Evident",
Indekseri
Ponekad je kolekciji unutar klase bolje pristupiti kao da je klasa polje. Pretpostavimo,
na primjer, da ste stvorili kontrolu padajueg popisa myListBox koja sadri popis nizova
koji su spremljeni u jednodimenzionalnom polju, privatnoj varijabli lanici myStrings.
Kontrola padajueg popisa sadri svojstva i metode lanove te svoje polje nizova. Meu-
tim, prikladno bi bilo polju padajueg popisa pristupiti s pomou indeksa, kao da se
radi o polju.' Na primjer, takvo bi svojstvo doputalo sljedee iskaze:
string theFirstString = my!istBox[o];
string theLastString = myListBox[!ength-l];
Povratni tip odreuje tip objekta koji e indekser vratiti, dok argument tipa odreuje
kakav e se argument koristiti za indeksiranje kolekcije koja sadri ciljne objekte.
Iako se za vrijednosti indeksa obino koriste cjelobrojne vrijednosti, kolekciju moete
indeksirati i s drugim tipovima, ukljuujui nizove. Moete ak i puiti indekser s vie
parametafa da biste stvorili viedimenzionalno polje!
Kljuna rije th is slui kao referenca objekta u kojem se indekser pojavljuje. Kao i za
ostala svojstva, morate definirati pristupnike get i set koji odreuju kako e se zatra-
eni objekt uzeti iz kolekcije ili se dodati u nju.
Stvarna kontrola ListBox, dostupna u Windows Forms i ASP.NET, ima kolekciju Items koja implementira
indekser.
184 | Programiranje C#
u primjeru 9-9 deklarirana je kontrola padajueg popisa (ListBoxTest) koja sadri jed-
nostavno polje (myStrings) i jednostavni indekser za pristupanje sadraju.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace Simplelndexer
{
/ / Pojednostavnjena kontrola ListBox
public class ListBoxTest
{
private stringl] strings;
private int ctr = 0 ;
strings[ctr++] = s;
}
}
// Obrauje lo indeks
}
else
strings[ctr++] = theString;
{
get
{
U Obrauje lo indeks
return strings[index];
}
set
}
}
// Objavljuje koliko ima nizova
public int GetNumEntries()
{
return ctr;
}
// Testira pristup
string subst = "Universe";
lbt[l] = subst;
}
}
}
}
186 | Programiranje C#
Kako bi primjer 9-9 bio to jednostavniji, kontrolu padajueg popisa sveli smo na
nekoliko znaajki koje su nam bitne. Popis zanemaruje sve to ima veze s korisnikom
kontrolom i fokusira se samo na popis nizova koje padajui popis odrava i na metode
za rad s njima. U stvarnoj aplikaciji ovo je, naravno, samo mali dio metoda padajueg
popisa iji je glavni zadatak prikaz nizova i omoguavanje izbora.
prvo treba obratiti panju na dva privatna lana:
private string[] strings;
private int ctr = 0;
Padajui popis u ovom programu odrava jednostavno polje nizova: strings. Ponovno,
u pravom biste padajuem popisu vjerojatno koristili sloeniji i dinaminiji spremnik,
na primjer he-tablicu (engl. hash table). Varijabla lanica c tr prati koliko je nizova
dodano ovom polju.
Polje u konstruktoru incijalizirajte iskazom:
strings = new String[256];
Ostatak konstruktora polju dodaje parametre. Novi se nizovi, ponovno radi jednostav-
nosti, polju dodaju redoslijedom primanja.
Sintaksa indeksera vrlo je slina sintaksi svojstava. Postoji metoda get (), metoda se t()
ili obje. U prikazanom primjeru metoda g et() implementira osnovnu provjeru granica
te, pod pretpostavkom da je zatraeni indeks prihvatljiv, vraa zatraenu vrijednost:
get
{
if (index < 0 [| index >= strings.Length)
{
// Obrauje lo Indeks
}
return strings[index];
}
Metoda s e t() provjerava da li indeks koji postavljate ve ima vrijednost u padajuem
popisu. Ako nema, ona postavku tretira kao pogreku (novi se elementi u ovom pri-
stupu mogu dodati samo s pomou Add). Pristupnik set iskoritava prednost implicit-
nog parametra value koji predstavlja sve ono to je dodijeljeno s pomou indeksnog
operatora:
In d ekseri i d o d je ljiv a n je
U primjeru 9-9 ne moete dodijeliti indeksu koji nema vrijednost. Stoga, ako
napiete:
lbtjlO] = "wow! ;
{
// Dodavanje samo kroz metodu za dodavanje
if (index >= strings.Length )
{
// Obrauje pogreke
}
else
{
strings[index] = value;
if (ctr < index+l)
ctr = index+l;
}
}
188 | Programiranje C#
jzlaz e biti:
lbt[0] Hello
lbt[1] Universe
lbt[2] Who
lbt[3] Is
lbt[4] lohn
lbt[5] Galt
lbt[6]
lbt[7]
lbt[8]
lbt[9]
lbt[10 : wow!
u Main() se stvara instanca klase ListBoxTest pod nazivom lbt i dva se niza proslje-
uju kao parametri:
ListBoxTest lb t = new ListBoxTest("Hello", "World");
Prije p rov jere v rije d n o sti m od ificira se druga v rijedn ost (s indeksom 1):
string subst = Universe";
l b t [i ] = subst;
using 5ystem;
using 5ystem.Collections.Ceneric;
using System.Text;
Kendregion
namespace Overloadedlndexer
{
// Pojednostavnjena ListBox kontrola
public class ListBoxTest
{
private string[] strings;
private int ctr = 0;
190 j Programiranje C#
primjer 9-10. Preoptereimnje indeksa (nastavak)
private int findString( string searchString )
{
for ( int i = 0; i < strings.Length; i++ )
{
if ( strings[i].StartsWith( searchString ) )
{
return i;
}
}
return -i;
// Indeksiranje nizom
public string this[string index]
{
get
{
if ( index.Length == o )
{
// Obrauje lo indeks
}
I I Testira pristup
string subst = "Universe";
lbt[l] = subst;
lbt["Hel"j = "GoodBye";
U lbt["xyz"] = "oops";
192 | Programiranje C#
Suelja kolekcija
NET kostur prua dva skupa standardnih suelja za enumeriranje i usporeivanje
kolekcija: tradicionalne (nesigurne za tipove) i nove, sigurne za tipove, generike kolek-
cije. U ovoj knjizi usredotoit emo se na nova suelja kolekcija sigurna za tipove jer
su takva suelja mnogo bolja.
Suelje ICollection bilo kojeg specifinog tipa moete deklarirati tako da opi tip u
deklaraciji suelja (<T>) zamijenite stvarnim tipom (na primjer, int ili string).
#>
N a p o m e n a z a C++ p r o g r a m e r e : generici jezika C # su po sintaksi i upo-
trebi slini predlocima u jeziku C++. Meutim, budui da se gene-
riki tipovi proiruju u specifian tip tijekom izvoenja, J IT prevoditelj
moe dijeliti kod izmeu vie instanci, te je kod znatno krai od onog
koji se generira upotrebom C++ predloaka.
T a b lica 9 - 2 . S u e l ja k o l e k c i j a
Suelje Svrha
ICollection<T> Osnovno suelje za generike kolekdje.
ICollection<T> Implementiraju ga sve kolekdje jer prua metodu CopyTo( ), kao i svojstva Count,
IsSynchronized i SyncRoot.
IComparer<T> Usporeuje dva objekta unutar kolekdje kako bi se kolekcija mogla sortirati.
lComparable<T>
Suelje IEnumerable<T>
Iskaz foreach u ListBoxTest moete podrati implementacijom suelja IEnumerable<T>
(pogledajte primjer 9-11). IEnumerable sadri samo jednu metodu, GetEnumerator()
koja vraa implementaciju suelja IEnumerator<T>. Jezik C# prua posebnu pomo pri
stvaranju enumeratora, koritenjem nove kljune rijei yield.
P r im j e r 9 - 1 1 . ListBox k a o k l a s a k o j a s e m o e e n u m e r i r a t i
using System;
us ing System.Collections.Generic;
#endregion
namespace Enumerable
{
public class ListBoxTest : IEnumerable<String>
{
private string[] strings;
private int ctr = 0;
// Klase koje se mogu nenumerirati mogu vratiti enumerator
public IEnumerator<string> GetEnumerator()
{
foreach ( string s in strings )
{
yield return s;
}
}
194 | Programiranje C#
frimj e r ^ ~ ' - ' s* Box k ao klasa koja se moe enumerirati (nastavak)
strings[index] = value;
}
}
// Objavljuje koliko nizova ima
public int GetNumEntries()
{
return ctr;
}
// Testira pristup
string subst = "Universe";
lbt[1 j = subst;
Velika promjena u ovoj inaici programa je pozivanje petlje foreach koja uzima svaki
niz iz padajueg popisa. Petlja foreach automatski koristi suelje IEnumerable<T> pozi-
vajui metodu GetEnumerator().
Ogranienja
Ponekad morate osigurati da su elementi koje dodajete generikom popisu u skladu s
odreenim ogranienjima (npr. da su izvedeni iz odreene osnovne klase ili da imple-
mentiraju odreeno suelje). U sljedeem primjeru implementirat emo pojednosta-
vljen jednostruko povezan popis koji se moe sortirati. Popis se sastoji od vorova
(Nodes) i svaki Node mora zadovoljavati uvjet da tipovi koji mu se dodaju implementi-
raju suelje IComparer. To moete uiniti sljedeim iskazom:
public class Node<T> :
IComparable<Node<T>> where T : IComparable<T>
Ovaj iskaz definira generiki Node koji sadri tip T. Node T implementira suelje ICompa-
rable<T>, to znai da se dva vora T mogu usporediti. Klasa Node je ograniena (where
T : IComparable<T>) na samo one tipove koji implementiraju suelje IComparable. Tip T,
stoga, moete zamijeniti bilo kojim tipom koji implementira suelje IComparable.
U primjeru 9-12 prikazana je cjelokupna implementacija koja je analizirana u sljede-
im odlomcima.
namespace UsingConstraints
{
public class Employee : IComparable<Employee>
{
private string name;
public Employee(string name)
{
this.name = name;
}
public override string To String O
{
return this.name;
}
U Implementira suelje
public int CompareTo(Employee rhs)
{
return this.name.CompareTo(rhs.name);
}
196 | Programiranje C#
primjer 9-12. Upotreba ogranienja (nastavak)
// Konstruktor
public Node(T data)
{
this.data = data;
}
I I Svojstva
public T Data { get { return this.data; } }
I I Metode
public Node<T> Add(Node<T> newNode)
{
if (this.CompareTo(newNode) > 0) I I ide prije mene
{
newNode.next = this; I I novi vor pokazuje na mene
return this;
}
}
public override string To St ri ng O
if (next != nuli)
return output;
}
} // Kraj klase
// Svojstva
// Indekser
public T this[int index]
198 | Programiranje C#
Primjer 9-12. Koritenje ogranienja (nastavak)
{
get
{
int ctr = o;
Node<T> node = headNode;
if (ctr == index)
{
return node.Data;
}
else
{
node = node.Next;
}
++ctr;
} // Kraj while
throw new ArgumentOutOfRangeException();
} // Kraj get
} // Kraj indeksera
// Konstruktor
public LinkedList()
{
}
// Metode
public void Add(T data)
{
if (headNode == nuli)
{
headNode = new Node<T>(data);
else
{
headNode = headNode.Add(new Node<T>(data));
}
public override string ToStringO
if (this.headNode != nuli)
{
return this.headNode.ToStringO;
else
{
return string.Empty;
}
}
}
Console.Writeline("\nRetrieving collections..
Ova deklaracija govori kako se objekti Employee mogu usporediti i vidimo da klasa
Employee implementira potrebne metode (CompareTo i Equals). Ove metode su sigurne
za tipove (one znaju da e proslijeeni parametar pripadati tipu Employee). U dekla-
raciji za, LinkedList odreeno je da taj popis sadri samo tipove koji implementiraju
suelje IComparable:
public class LinkedList<T> where T : IComparable<T>
te je mogunost sortiranja popisa zajamena. LinkedList sadri objekt tipa Node. Node
takoer implementira suelje IComparable i zahtijeva da svi objekti koje sadri kao
podatke i sami implementiraju suelje IComparable;
200 | Programiranje O
public class Node<T> :
lComparable<Node<T>> where T : IComparable<T>
List<T>
Klasini problem s tipom Array je njegova fiksna veliina. Ako unaprijed ne znate
koliko e objekata polje sadrati, postoji rizik deklariranja premalog polja (pa e pone-
stati prostora) ili prevelikog polja (pa e se potroiti previe memorije).
Program koji piete e od korisnika moda zatraiti unos ili e uzimati podatke s Web
stranice. Kada pronae objekte (nizove, vrijednost itd.) dodat e ih u polje, ali vi neete
znati koliko ete objekata prikupiti u odreenoj sesiji. Klasino polje fiksne veliine
nije dobar izbor jer ne moete predvidjeti veliinu polja koje e vam biti potrebno.
Klasa L ist je polje ija se veliina prema potrebi dinamiki poveava. Poljima List se
moe upravljati s pomou raznih metoda i svojstava koja ona sadre. U tablici 9-3 pri-
kazane su najvanije metode i svojstva.
T a b lica 9 - 3 . M e t o d e i s v o j s t v a p o l j a L is t
p:.'
f Metoda ili svojstvo Svrha
Capacity Svojstvo za postavljanje ili uzim anje broja elem enata koje polje L i s t m oe sadrati. Ova se
vrijednost autom atski poveava ako broj elem enata premauje kapacitet. Ovu vrijednost m oete
postaviti kako biste sm anjili broj ponovnih alokacija te m oete pozvati m etodu T r i m ( ) za sma-
njivanje ove vrijednosti na stvarni broj elem enata C o u n t.
Count Svojstvo za uzim anje broja elem enata koje polje trenutno sadri.
BinarySearch() Preoptereena javna m eto d a koja koristi binarno pretraivanje za pronalaenje odreenog
e lem en ta u sortiranom L i s t .
1 Idiom u FCL-u je da prui element I tem za klase kolekcija koji je u Cd implementiran kao indekser.
Prilikom stvaranja List ne definira se broj elemenata koje e ono sadrati. Elementi se
u List dodaju s pomou metode Add(), a polje samo vodi brigu o broju svojih eleme-
nata, kao to je prikazano u primjeru 9-13.
P r i m j e r 9 - 1 3 . R a d s p o l j e m L is t
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace ListCollection
{
// Jednostavna klasa koja e uvati u List
public class Employee
{
private int empID;
202 | Programiranje C#
i p rim jer 9 - 1 3 . R a d s p o l j e m L is t ( n a s ta v a k )
}
public ovferride string ToStringO
{
return empID.ToStringO;
}
public int EmpID
{
get
{
return empID;
}
set
{
empID = value;
}
}
}
public class Tester
{
static void Main()
{
// Popunjava List
for ( int i = 0; i < 5; i++ )
{
empList.Add( new Employee( i + 1 0 0 ) );
intList.Add( i * 5 );
}
Console.WriteLine( "\n" );
Console.WriteLine( "\n" );
Console.WriteLine( "empList.Capacity: {0}",
empList.Capacity );
}
}
}
Kapacitet moete runo postaviti na bilo koji broj jednak ili vei od broja elemenata.
Ako ga postavite na broj manji od broja elemenata, program e izbaciti iznimku tipa
Argument0ut0fRangeException.
return t his.emp ID . C om pa re To ( r . em p I D) ;
204 ( Programiranje C#
f^da ste spremni za sortiranje popisa zaposlenika empList. Kako biste provjerili funk-
cionira 1' sortiranje, trebate cjelobrojne vrijednosti i instance Employee dodati odgo-
varajuim poljima s nasuminim vrijednostima. Za stvaranje nasuminih vrijedno- s
t i instancirajte objekt klase Random. Za generiranje nasuminih vrijednosti pozovite
metodu Next() na objektu Randomkoja e vratiti pseudonasumini broj. Metoda Next()
% se preoptereuje, jedna inaica omoguava prosljeivanje cjelobrojne vrijednosti koja
t predstavlja najvei eljeni nasumini broj. U ovom se primjeru prosljeuje vrijednost
1 10 za generiranje nasuminog broja izmeu 0 i 10:
Random r = new Random();
r.Next(l0);
U primjeru 9-14 stvoreno je polje cjelobrojnih vrijednosti i polje Employee, oba se ispu-
njavaju nasuminim brojevima i njihove se vrijednosti ispisuju. Oba se polja zatim
sortiraju i ispisuju se nove vrijednosti.
using System;
using Sy5tem.Collections.Generic;
using System.Text;
.#endregion
namespace IComparable
{
// Jednostavna klasa koja e uvati u polju
public class Employee : IComparable<Employee>
{
private int empID;
// Popunjava polje
tor ( int i = 0; i < 5; i++ )
{
// Dodaje sluajni identifikator zaposlenika
empArray.Add( new Employee( r.Next( 10 ) + 100 ) );
206 | Programiranje Q
p r im jer 9 -1 4 . S o r t ir a n je p o l j a c j e lo b r o jn ih v r ijed n o s t i i p o l ja E m p lo y e e ( n a s ta v a k )
}
Console.WriteLine( "\n" );
empArray.Sort();
U izlazu se moe vidjeti kako su polje cjelobrojnih vrijednosti i polje Employee generi-
rani s nasuminim brojevima. Nakon sortiranja u izlazu se vidi kako su vrijednosti
ispravno poredane.
P r im j e r 9 - 1 5. S o r t i r a n j e p o l j a p r e m a I D - o v i m a z a p o s l e n i k a i g o d i n a m a s t a a
using System;
using System.Collections.Generic;
using System.Text;
ttendregion
namespace IComparer
{
public class Employee : IComparable<Employee>
208 1 Programiranje C#
ifritnjer 9-15- Sortiranje polja prema ID-ovima zaposlenika godinama staa (nastavak)
this.empID = empID;
public Employee.EmployeeComparer.ComparisonType
WhichComparison
{
get{return whichComparison;}
set{whichComparison = value;}
}
}
}
public class Tester
{
210 | Programiranje C#
Primjer 9-15. Sortiranje polja prema ID-ovima zaposlenika i godinama staa (nastavak)
static void Main()
{
List<Employee> empArray = new List<Employee>();
// Popunjava polje
for ( int i = 0; i < 5; i++ )
{
// add a random employee id
empArray.Add(
new Employee(
r.Next( 10 ) + ioo, r.Next( 20 )
);
}
Console.WriteLine( "\n" );
Console.WriteLine( "\n" );
c.WhichComparison = Employee.EmployeeComparer.ComparisonType.Yrs;
empArray.Sort( c );
Console.WriteLine( "\n" );
}'
}
Redovi
Red (engl. queue ) predstavlja kolekciju koja funkcionira na naelu prvi-unutra, prvi-
van (engl. first in, first out, FIFO). Obino se usporeuje s redom osoba koje ekaju
na blagajni kako bi kupili kartu. Prva osoba u redu trebala bi biti i prva osoba koja
kupuje kartu i izlazi iz reda.
Red je kolekcija koju je zgodno koristiti ako upravljate ogranienim resursom. Na
primjer, moda ete trebati poslati poruke resursu koji istovremeno moe obraditi
samo jednu poruku. U tom biste sluaju stvorili red poruka kako biste svojim klijen-
tima mogli rei: Vae su nam poruke bitne i zato se obrauju redoslijedom kojim su
primljene."
Klasa Oueue ima razne metode i svojstva koja su prikazana u tablici 9-4.
Elemente moete dodati u red naredbom Enqueue, a iz reda ih moete ukloniti nared-
bom Dequeue ili s pomou enumeratora. Te su operacije prikazane u primjeru 9-16.
212 | Programiranje C#
P rim jer 9-16. R ads redovima
(tregion Using direct ives
using $ystem;
using System.Collections.Ceneric;
using System.Text;
#endregion
namespace Oueue
{
public class Tester
{
static void Main ()
{
U Popunjava polje
for ( int i = O; i < 5 ; i++ )
intOueue.Enqueue( i * 5 );
// Prikazuje red
Console.Write( "intOueue values:\t" );
PrintValues( intOueue );
// Prikazuje red.
Console.Write( "intOueue values:\t" );
PrintValues( intOueue );
// Prikazuje red.
Console.Write( "intOueue values:\t" ) ;
PrintValues( intQueue );
I I Prikazuje red.
Console.Write( "intQueue values:\t" );
Stogovi
Stog (engl. stack ) je kolekcija koja funkcionira na naelu posljednji-unutra, prvi-van
(engl. last in, first out, LIFO), poput hrpe tanjura na vedskom stolu ili hrpe novia
na vaem stolu. S gomile ete najprije uzeti tanjur koji stoji na vrhu (a on je posljednji
dodan na hrpu).
Osnovne metode za dodavanje na stog i uklanjanje sa stoga su Pushf) i Pop(). Stack,
kao i Oueue, nudi i metodu Peek(). Najvanije metode i svojstva klase Stack prikazani
su u tablici 9-5.
214 | Programiranje C#
tablica 9 -5 . Metode i svojstva stoga (nastavak)
Tipovi L ist, Oueue i Stack sadre preoptereene metode CopyTo() i ToArray() za kopira-
nje elemenata u polje. U sluaju Stack metoda CopyTo() e kopirati elemente u postojee
jednodimenzionalno polje, prepisujui sadraj polja poevi od indeksa koji zadate.
Metoda ToArray() vraa novo polje u kojem se nalazi sadraj elemenata stoga. To je
prikazano u primjeru 9-17.
P rim jer 9 -1 7 . R a d s a s t o g o m
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace Stack
{
public class Tester
{
static void Main()
{
Stack<Int3 2 > intStack = new Stack<Int32>();
// Popunjava polje
// Prikazuje stog.
Console.Write( "intStack values:\t" );
PrintValues( intStack );
// Prikazuje stog.
// Prikazuje stog.
Console.Write( "intStack valuesrVt" );
PrintValues( intStack );
// Prikazuje stog.
Console.Write( "intStack values'.Vt" );
1 PrintValuesj intStack );
}
public static void PrintValues(
IEnumerable<IntB2> myCollection )
^ IEnumerator<Int32> enumerator =
myCollection.GetEnumerator();
while ( enumerator.MoveNext() )
Console.Write( "{0} ", enumerator.Current );
Console.WriteLine();
216 ) Programiranje C#
Izlazu se vidi kako se elementi dodani stogu uklanjaju obrnutim redoslijedom.
||nakCopyTo() moe se vidjeti pregledom ciljnog polja prije i nakon pozivanja metode
|jjyTo()- Elementi polja se prepisuju poevi od zadanog indeksa (6).
.jenici
? R j e n i k (engl. dictionary) je kolekcija koja klju povezuje s vrijednosti. U rjeniku odre-
It:em() lndekserzaDictionary.
Keys Javno svojstvo koje uzima kolekciju s kljuevima za Dictionary (pogledajte i svojstvo Values).
Values Javno svojstvo koje uzima kolekciju koja sadri vrijednosti u Dict ionary (pogledajte i svojstvo
Keys).
Klju u klasi Dictionary moe biti primitivni tip ili instanca korisniki definiranog
tipa (objekt). Objekti koji se koriste kao kljuevi u Dictionary moraju implementirati
metode GetHashCode() i Equals. U veini sluajeva moete jednostavno koristiti nasli-
jeenu implementaciju izO bject.
IDictionary<K,V>
Rjenici implementiraju suelje IDictionary<K,V> (K oznaava tip kljua, a V oznaava
tip vrijednosti). IDictionary prua javno svojstvo Item. Ono vraa vrijednost sa zada-
nim kljuem. Deklaracija svojstva Item u C# glasi:
V[K key]
{get; set;}
218 | Programiranje C#
ijjrimjer 9-18 poinje instanciranjem novog Dictionary. Tip kljua i vrijednosti dekla-
gjranisu kao string.
Ako kao klju koristite referentni tip i taj tip moe mutirati (nizovi ne
mogu mutirati), ne smijete mijenjati vrijednost objekta kljua nakon
to ga ponete koristiti u rjeniku.
Nekad su ljudi kupovali raunala iskljuivo zbog obrade brojanih vrijednosti. Prva
raunala su se najprije koristila za izraun putanje projektila (iako neki nedavno obja-
vljeni dokumenti otkrivaju kako su se koristila i za deifriranje). U svakom sluaju,
neko se programiranje uilo na katedrama za matematiku velikih sveuilita, a infor-
matika se smatralo matematikom disciplinom.
Danas se veina programa bavi nizovima slova, a ne nizovima brojeva. Ti se nizovi
obino koriste za obradu rijei, rad s dokumentima i stvaranje Web-stranica.
C # prua ugraenu podrku za potpuno funkcionalan tipa string. to je jo vanije,
C # nizove tretira kao objekte koji uahuruju sve metode za manipulaciju, sortiranje i
pretraivanje koje se obino primjenjuju na niz slova.
Objekti ICloneable mogu stvoriti nove instance s istom vrijednosti koju imaju izvorne
instance. U ovom je sluaju mogue klonirati niz kako bi se proizveo novi niz koji sadri
iste vrijednosti kao izvorni niz. Klase ICloneable implementiraju metodu Clone().
Redanje niza je jedna od brojnih leksikih operacija koje djeluju na vrijednost niza i u obzir uzimaju kul-
turoloke informacije koje se temelje na eksplicitno deklariranoj kulturi ili na implicitnoj tekuoj kulturi..
Stoga, ako je trenutna kultura American English (kao to je pretpostavljeno u cijeloj ovoj knjizi), metoda
Compare smatra kako je a manje od ,,A. Metoda CompareOrdinal usporeuje redoslijed i stoga je, bez
obzira na kulturu, a vee od ,,A.
S tv aran je n izova
Nizovi se najee stvaraju tako da se niz znakova pod navodnicima, to se naziva
literalom niza., dodijeli varijabli tipa string koju je korisnik deklarirao:
string newString = "This is a string literat ;
Nizovi pod navodnicima mogu sadrati i kontrolne znakove (engl. escape characters),
kao to su \n i \t, koji poinju obrnutom kosom crtom (\). Dva ranije navedena znaka
slue za oznaavanje prijelaza u novi red, odnosno novi tabulator.
Nizovi se mogu stvoriti i s pomou doslovnih literala nizova (engl. verbatim string
literals), koji poinju simbolom @ . To konstruktoru String govori kako se niz moe
koristiti doslovno, ak i ako zauzima vie redova ili sadrava kontrolne znakove. U
doslovnom literalu niza obrnute kose crte i znakovi iza njih smatraju se samo dodat-
nim znakovima u nizu. Stoga su sljedee dvije definicije jednake.
string literalOne = " NNNNf^ ste m N V^Directo^NNProgrammingCit.cs";
string verbatimliteralOne =
[S)"\\MySystem\MyDirectory\ProgrammingC# cs";
U prvom redu koristi se literal niza koji nije doslovan te se obrnuta kosa crta mora
izdvojiti11. To jest, ispred nje se mora napisati druga obrnuta kosa crta. U drugom se
redu koristi doslovan literal niza pa dodatna obrnuta kosa crta nije potrebna. Drugi
primjer prikazuje doslovne nizove u vie redova:
222 | Programiranje C#
string literalTwo = "Line OneNnLine Two";
string verbatimLiteralTwo = @"Line One
Line Two";
(TJ,
I Ako unutar doslovnog niza imate dvostrukenavodnike, morateihizdvo-
uV kako prevoditelj znao na kojem mjestu se doslovni niz zavrava
Ove su deklaracije ponovno istoznane. Moete koristiti onu koja vam se ini priklad-
nija ili jednostavnija.
Metoda ToStringO
Jo jedan nain stvaranja nizova jest pozivanje metode ToStringO na objekt i dodje-
ljivanje rezultata varijabli niza. Svi ugraeni tipovi premouju ovu metodu kako bi
se pojednostavila pretvorba vrijednosti (esto se radi o brojanoj vrijednosti) u njenu
nizovnu reprezentaciju. U sljedeem se primjeru metoda ToStringO tipa cjelobrojne
vrijednosti poziva za spremanje svoje vrijednosti u niz:
int mylnteger = 5 ;
string integerString = mylnteger.ToStringO;
Poziv metode mylnteger. ToStringO vraa objekt String koji se zatim dodjeljuje inte-
gerString.
Klasa String prua brojne preoptereene konstruktore koji podravaju razliite teh-
nike za dodjelu vrijednosti niza tipovima string. Neki od tih konstruktora omogua-
vaju vam stvaranje niza prosljeivanjem polja znakova ili pokazivaa na znak. Proslje-
ivanje polja znakova kao parametra konstruktoru String stvara novu instancu niza
kompatibilnu s CLR-om. Za prosljeivanje pokazivaa na znak potreban je marker
unsafe koji je objanjen u poglavlju 22.
Rad s nizovima
Klasa string prua razne metode za usporedbu, pretraivanje i rad s nizovima, a naj-
vanije su prikazane u tablici 10-1.
T a b l i c a 1 0 -1 . M e t o d e i p o l j a z a k l a s u strin g
Join() Preoptereena javna statika metoda koja ulanava zadani nizizmeu svakog elementa polja
nizova.
Lastlndex0f() Daje indeks posljednje pojave odreenog znaka iliniza unutar niza.
PadLeft() Znakove u nizu poravnava desno, dok lijevustranu popunjava razmacima ilizadanim znakom.
PadRight() Znakove u nizu poravnava lijevo,dok desnu stranu popunjava razmacima ilizadanim znakom.
Trim() Uklanja sve pojave skupa zadanih znakova spoetka izavretka niza.
P r im je r 20-2. R a d s n i z o v im a
using System;
using Syst
e m.Collections.Generic;
using System.Text;
#endregion
namespace WorkingWithStrings
{
224 | Programiranje C#
p r im jer 1 0 -1 . R a d s n iz o v im a ( n a s t a v a k )
Prva dva niza su literali nizova, a trei je doslovni literal niza. Prvo se s i usporeuje
sa s2. Metoda Compare() je javna statika metoda klase string i preoptereena je. Prva
preoptereena inaica uzima dva niza i usporeuje ih:
// Usporeuje dva niza i pritom razlikuje velika i mala slova
result = string.Compare(sl, s2);
Console.WriteLine("compare si: {0}, s2: {1}, result: {2}\n",
si, s2, result);
226 | P ro g ra m ira n je C#
Ova usporedba razlikuje mala i velika slova te moe vratiti razliite vrijednosti, ovisno
0 rezultatima usporedbe:
Negativan cijeli broj ako je prvi niz manji od drugog niza
Nulu ako su nizovi jednaki
Pozitivan cijeli broj ako je prvi niz vei od drugog niza
U ovom sluaju izlaz pokazuje kako je si manji od s2. U Unicodeu (kao i u ASCII-ju)
malo slovo ima manju vrijednost od velikog slova:
compare si: abcd, s2: ABCD, result: -1
Druga usporedba koristi preoptereenu inaicu metode Compare() koja uzima trei,
Boolean, parametar ija vrijednost odreuje treba li se u usporedbi zanemariti razlika
izmeu velikih i malih slova. Ako je vrijednost ovog parametra zanemari razliku"
true, usporedba se izvodi bez obzira na razliku izmeu velikih i malih slova, kao u
sljedeem primjeru:
result = string.Compare(sl,s2, true);
Console.WriteLine("compare insensitive\n");
Console.WriteLine(s4: {0 }, s2 : {l}, result: {2 }\n",
si, s2, result);
---- 1
' Rezultat je ispisan sava iskaza WriteLine() kako bi redovi bili dovoljno
^ kratki za tiskanje u knjizi.
Ovog se puta razlika izmeu velikih i malih slova zanemaruje i rezultat je nula, to
oznaava kako su dva niza identina (bez obzira na razliku izmeu velikih i malih
slova):
compare insensitive
Slino tome se i kopiranje niza moe izvesti na dva naina. Prvi je s pomou statike
metode Copy():
string s8 = string.Copy(s7);
Klasa String prua tri naina za provjeru jednakosti dva niza. Prvo, moete koristiti
preoptereenu metodu Equals() i izravno upitati s9 ima li s8 istu vrijednost:
Console.WriteLine("\nDoes s9.Equals(s8)?: {o}",
s9.Equals(s8));
Drugi je nain prosljeivanje oba niza do statike metode Equals() klase String:
Console.WriteLine(''Does Equals(s9,s8)?: {0}",
string.Equals(s9,s8));
Sljedeih par redova u primjeru 10-1 koristi indeksni operator ([]) za traenje zadanog
znaka unutar niza, a svojstvo Length koriste za vraanje ukupne duljine niza:
Console.WriteLine('\nString s9 is {0} characters long.",
s9.Length);
Console.WriteLine("The 5th character is {l}\n",
s9.Length, s9[4]);
Rezultat je sljedei:
String s9 is 8 characters long.
The 5 th character is A
Metoda EndsWith() pita niz da li se na zavretku niza nalazi podniz. Stoga, s3 moete
prvo pitati zavrava li s Training (to nije sluaj), a zatim zavrava li s Consulting (to
je istinito):
I I Testira da li niz zavrava sa skupom znakova
Console.WriteLine( "s3:{o}\nEnds with Training?: {l}\n",
s3,
s3.EndsWith( "Training" ) );
Console.WriteLine(
"Ends with Consulting?: {o}",
s3.EndsWith( "Consulting" ) );
U izlazu se moe vidjeti kako prva provjera nije uspjela, a druga jest:
s3:Liberty Associates, Ine.
provides custom .NET development,
on-site Training and Consulting
Ends with Training?: False
Ends with Consulting?: True
228 | Programiranje C#
M etoda IndexOf() u n u ta r niza locira podn iz,
u kopiju izv orn og niza.
a metoda In sert() umee novi podniz
Tu vrijednost zatim moete koristiti za umetanje rijei excellent i razmaka u tai niz
Rije se, zapravo, umee u kopiju niza koju vraa metoda In serti) i zatim se dodie
ljuje nizu slO: aoaje-
Traenje podnizova
Tip String prua preoptereenu metodu Substring() kojom se iznizova izdvajaju pod-
mzovi. Obje inacice uzimaju indeks koji oznaava poetak izdvajanja, a jedna od dvije
mac.ce uzima i drugi indeks koji oznaava gdje zavriti operaciju. Metoda Substring )
ilustrirana je u primjeru 1 0 -2 . angu
using System;
using System.Collections.Generic;
using System.Text;
ftendregion
namespace SubString
int ix;
U nuli ,
string s5 = s l. Su bs tn ng ( ix + l J,
230 | Programiranje C#
:t,;mjer 10-2. Koritenje metode SubstringO (nastavak)
Console. Writ eLin e( "s2: {0}\ns3: {l}", s2, s3 );
Cons ole. Writ eLin e( "s4: {0}\ns5: {l}\n", s4, s5 );
Cons ole. Writ eLin e( "si: { 0 }\ n, si );
% }
i}
si: One
|o rjeenje nije elegantno, ali funkcionira i ilustrira upotrebu Substring. Ona nalikuje
'otrebi aritmetike pokazivaa u C++, ali nema pokazivaa niti nesigurnog koda.
Seljenje nizova
inkovitije rjeenje problema prikazanog u primjeru 10-2 jest koritenje metode
i t ( ) klase String koja slui za razlaganje nizova na podnizove. Za koritenje
|ode S p lit() treba proslijediti polje graninika (znakovi koji oznaavaju mjesto
:le rijei), a metoda vraa polje podnizova. Upotreba ove metode prikazana je u
lmjeru 10-3
p t je r 1 0 -3 . K o r i t e n j e m e t o d e S p lit()
)hg System;
ng System.Collections.Generic;
(g. System.Text;
Tegion
namespaceStringSplit sj
{ 1
public class StringTester
static voidMain() *
{ )
// Pravi nizove 5 kojima emo raditi
string si = "One,Two,Three Liberty Associates, Ine.1;
Ponite s inicijalizacijom izlaza na prazan niz, a zatim izlazni niz sagradite u etin
koraka. Ulanajte vrijednost c tr. Zatim dodajte dvotoku, zatim podniz koji je vratilo
232 | Programiranje C#
dijeljenje, a zatim novi red. Prilikom svakog se ulanavanja stvara nova kopija niza,
, i sva se etiri koraka ponavljaju za svaki podniz koji metoda StringO pronae. Ovo
; ponavljanje kopiranja niza je vrlo neuinkovito.
i
problem je u tome to tip niza nije predvien za ovakvu operaciju. Vi zapravo elite
$ stvoriti novi niz dodavanjem formatiranog niza kroz petlju. Potrebna vam je klasa
% StringBuilder.
|p|pda Objanjenje
Chars (ndekser.
A ppendj) Preoptereena javna m etoda koja niz znakova dodaje na zavretak trenutnog S t r in g B u ild e r .
AppendFormat ( ) Preoptereena javna m etod a koja specifikatore form ata zam jenjuj form atiranom vrijednosti
objekta.
- R e p la c e O Preoptereena javna m etoda koja sve instance zadanih znakova zam jenjuje novim znakovima.
Using System;
-Jising System.Collections.Generic;
tusing System,Text;
dfendregion
flamespace UsingStringBuilder
{
Space,
Comma
};
// Upotreba klase St ri ng Bu il de r za izgradn ju
// iz lazn og niza .
StringBuilder output = new StringBuilder();
int ctr = 1;
1: One
2: Two
3: Thr ee
4: Libe rty
5: As soc iates
6:
7 : Ine.
Ogranienja graninika
Budui da ste proslijedili graninike i za razm ake i za zareze, razm ak izm eu Assocu
ateS i Ine se vraa kao rije i num eriran je brojem 6 , kao sto je p rikazano. To n ]
ono to elite. K ako biste elim inirali ovu pojavu trebate m etodi S p lit reci da zarez
(kao onaj izmeu One, Two i Three), razm ak (kao onaj izm eu Liberty i Associates)
zarez iza kojeg slijedi razm ak tretira na isti nain. O va posljednja tnatca je najproble-
m atinija i za nju trebate koristiti regularni izraz.
234 | Programiranje C#
$ Takav je niz esto cijeli tekstualni dokument.
f Regularni izrazi se primjenjuju na nizove da bi se provjerilo odgovara li niz regular-
nom izrazu, da bi se vratio podniz ili novi niz koji predstavlja modifikaciju jednog
3- dijela izvornog niza (Ne zaboravite da su nizovi nepromjenjivi i stoga ih ni regularni
* izrazi ne mogu promijeniti).
* Primjenom ispravno sastavljenog regularnog izraza na sljedei niz:
One,Two,Three Liberty Associates, Ine.
? vraa se bilo koji ili svi pripadajui podnizovi (npr. Liberty ili One) ili modificirane ina-
ie pripadajuih podnizova (npr. LIBerTV ili OnE). Uinak regularnog izraza odreen
je sintaksom samog regularnog izraza.
Regularni se izraz sastoji od dva tipa znakova: literata i metaznakova. Literal je znak
* koji elite pronai u ciljnom nizu. Metaznak je poseban simbol koji slui kao naredba
za analizator (engl. parser) regularnih izraza. Analizator je stroj odgovoran za razumi-
jevanje regularnog izraza. Ako, na primjer, napiete regularni izraz:
,'(From|To| Subject |Date):
njemu e odgovarati svi podnizovi koji sadre rijei ,,Froin, ,,To, Subject" ili Date"
. i ako poinju novim redom (A) i zavravaju dvotokom (:).
Znak Au ovom sluaju analizatoru regularnih izraza govori kako traeni niz mora
poinjati novim redom. Rijei Froin" i ,,To su literali, a metaznakovi - lijeve i desne
zagrade (()) te okomite crte (|) - se koriste za grupiranje literala u skupove i oznaava-
nje kako se treba poklopiti bilo koja od opcija (A je takoer metaznak koji se koristi
za oznaavanje poetka reda).
r Stoga bi se sljedei red:
v A(From|To|Subject|Date):
5 mogao proitati kao: Pronai sve nizove koji poinju novim redom iza kojeg slijedi
bilo koji od etiri literala, From, To, Subject ili Date iza kojih slijedi dvotoka.
P r im je r 1 0 - 5 . K o r i t e n j e k l a s e Regex z a r e g u l a r n e iz r a z e
using System;
using System.Collections.Ceneric;
using System.Text;
using System.Text.RegularExpressions;
flendregion
namespace UsingRegEx
{
public class Tester
sBuilder.AppendFormat(
"{0}: {l}\n", id++, subString );
}
}
}
Primjer 10-5 poinje stvaranjem niza s i koji je identian nizu iz primjera 10-4:
string si = "One,Two,Three Liberty Associates, Inc.;
236 | Programiranje C#
tekstualni niz proslijeen konstruktoru regularan izraz u tradicionalnom smislu. Sa
ilita objektno orijentiranog jezika argument proslijeen konstruktoru je samo niz
%akova; theRegex je stvarni objekt regularnog izraza.
- .^.itak programa slian je ranijem primjeru 10-4, osim to se za niz s i umjesto
^ ^ e to d e S p lit() poziva metoda S p lit() klase Regex. Metoda R egex.Split() djeluje na
tfiti nain kao i metoda S trin g .S p lit() - vraa polje nizova kao rezultat usklaivanja
Iregularnog izraza unutar objekta theRegex.
-
:?faamespace RegExSplit
string si =
jf| "One,Two,Three Liberty Associates, Ine.";
Jj: StringBuilder sBuilder = new StringBuilder();
int id = l;
toreach ( string subStr in Regex.Split( si, " |, |," ) )
{
sBuilder.AppendFormat( "{0}: {l}\n , id++, subStr );
}
Console.WriteLine( "{o}", sBuilder );
}
using System;
using Sy stem .Col lec tions. Generic;
usin g System.Text;
using Sys tem.Te xt. Regul arExpre ssion s;
#endregion
{
class Test
if ( theMatch.Length != 0 )
}
}
}
}
}
U primjeru 10-7 stvoren je jednostavan niz koji treba pronai:
string stringl = "This is a test string ;
2B8 | Programiranje C#
Regex theReg = new Regex(@"(\S+)\s");
1? (i^iz \S pronalazi znak koji nije bjelina, a znak plus oznaava jedan ili vie. Niz\s (napi-
san malim slovom) oznaava bjelinu. Stoga se ovim nizom trae bilo kakvi znakovi
^oji nisu bjeline, a iza kojih slijedi bjelina.
Upamtite kako simbol (@) ispred niza stvara doslovni niz ime se izbje-
gava upotreba obrnute kose crte (\).
' U izlazu se moe vidjeti kako su pronaene prve etiri rijei. Posljednja rije nije pro-
'? naena jer iza nje ne slijedi bjelina. Ako umetnete razmak izmeu rijei string i ispred
ft zavrnih navodnika, program e pronai i tu rije.
i
i Svojstvo length je duljina pronaenog podniza i to je svojstvo objanjeno kasnije u
'> ovom poglavlju.
Koritenje R egex g ru p a
' Podnizove koji su pronaeni esto je korisno grupirati radi analize odgovarajueg
niza. Na primjer, moda ete htjeti pronai i grupirati sve IP adrese pronaene bilo
, Klasa Group omoguava stvaranje grupa rezultata na temelju sintakse regularnog izraza
' i predstavlja rezultate iz jednog izraza za grupiranje.
Izraz za grupiranje oznaava grupu i prua regularni izraz: u grupu e se dodati bilo
koji poniz koji odgovara regularnom izrazu. Na primjer, za stvaranje grupe ip moete
napisati:
-3? @"(?<ip>(\d|\.)+)\s"
ip Klasa Match izvodi iz Group i sadri kolekciju Groups u kojoj se nalaze sve grupe prona-
. ene s pomou Match.
Stvaranje i upotreba kolekcije Groups i klasa Group prikazana je u primjeru 10-8.
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
v/h
namespace RegExGroup
{
class Test
l l Grupa time = jedna ili vie znamenki ili dvotoki iza kojih slijedi bjelina
Regex theReg = new Regex( @"(?<time>(\d|\:)+)\s" +
// ip address = jedna ili vie znamenki iza kojih slijedi toka
@"(?<ip>(\d|\.)+)\s" +
// site = jedan ili vie znakova
(8"(?<site>\S+)" );
}
}
}
}
}
Primjer 10-8 ponovno poinje stvaranjem niza za traenje:
string st ringl = " 04:03:27 127.0.0 .0 Liber tyAsso ciates . com";
Ovaj niz moe biti jedan od mnogih koji su zabiljeeni u dnevniku Web posluitelja
ili koji su dobiveni kao rezultat pretraivanja baze podataka. U ovom jednostavnom
primjeru postoje tri stupca odvojena razmacima: jedan za vrijeme unosa zapisa, jedan
za IP adresu i jedan za stranicu. Naravno, kad rjeavate stvarni problem, moda ete
morati provesti sloenije upite i koristiti druge graninike i sloenija pretraivanja.
U primjeru 10-8 eljeli smo stvoriti jedan Regex objekt za pretraivanje nizova ovog
tipa koji bi se onda podijelili u tri grupe: time, ip address i s ite . Niz regularnog izraza
je prilino jednostavan te je primjer lako razumjeti. Meutim, upamtite kako biste u
240 | Programiranje C#
Istvarnom pretraivanju vjerojatno koristiti samo dio izvornog niza, a ne cijeli izvorni
Spiz kako je ovdje prikazano.
// grupa time = jedna ili vie znamenki ili dvotoki
// iza kojih slijedi bjelina
Regex theReg = new Regex((8"(?<time>(\d|\:)+)\s" +
// ip address = jedna ili vie znamenki ili toka
// iza kojih slijedi razmak
@"(?<ip>(\d|\.)+)\s" +
// site = jedan ili vie znakova
@"(?<site>\S+)");
g Zagrade slue za stvaranje grupe. Sve izmeu otvorene zagrade (neposredno ispred
upitnika) t zatvorene zagrade (u ovom sluaju nakon znaka +) je jedna neimenovana
gruPa-
Niz ?<time> toj grupi daje naziv time i grupa se povezuje odgovarajuim tekstom to
, jest regularnim izrazom ( \d|\: )+) \x'''. O vaj se regularni izraz moe interpretirati kao
T/ Je na **1vise znamenki, odnosno dvotoki iza kojih slijedi razmak.
Na slian nain niz ?<site> imenuje grupu site . Kao i primjer 10-7, i primjer 10-8 trai
'pkolekciju svih rezultata:
MatchCollection theMatches = theReg.Matches(stringi);
^ Primjer 10-8 prolazi kroz kolekciju Matches i pronalazi sve Match objekte.
1 Akie duljina (Length) objekta Match vea od nula, Match je pronaen; ispisuje se cijeli
I rezultat: 1
> Console.WriteLine(''\ntheMatch: {o}",
j theMatch.ToStringO);
Izlaz glasi:
*#
|i theMatch: 04:03:27 127.0.0,0 LibertyAssociates.com
U ovom primjeru theMatches sadri tri Match objekta. Svaki put se kroz vanjsku petlju
foreach pronalazi sljedei Match u kolekciji i prikazuje se njegov sadraj,
foreach (Match theMatch in theMatches)
Za svaki pronaeni Match objekt moete ispisati cijeli rezultat, razne grupe ili oboje.
242 | Programiranje C#
Snalaziti na jednom od dva poloaja. Kako biste te poloaje grupirali ujedan rezultat,
na dva mjesta u uzorku regularnog izraza stvorite grupu ?<company>:
Regex theReg = new Regex(@"(?<tirae>(\d|\:)+)\s" +
< @"(?<company>\S+)\s" +
@"(?<ip>(\dl\.)+)\s" +
M- @ (?<company>\S+)\s");
| Ova grupa regularnog izraza uzima sve odgovarajue nizove znakova koji se nalaze
iza time, ali i sve odgovarajue nizove koji se nalaze iza ip. Pomou ovog regularnog
i izraza moete analizirati sljedei niz:
string stringl = "04:03:27 lesse 0.0.0.127 Liberty
to se dogodilo? Zato grupa Company prikazuje Liberty? Gdje je prvi termin koji je
takoer pronaen? To se dogodilo jer je drugi termin prepisao prvi. Grupa je, meu-
tim, uhvatila oba termina. To se moe vidjeti u kolekciji Captures, kao to je prikazano
u primjeru 10-9.
P rim jer 1 0 -9 . I s p it iv a n j e k o l e k c i j e C a p t u r e s
using System;
using System.Collections.Generie;
using System.Text;
using System.Text.RegularExpressions;
%
(tendregion
namespace CaptureCollection
{
class Test
t {
// Niz za analiziranje
H obratite pozornost da se ime
H H pojavljuje na dva mjesta
string stringl =
04:03:27 3esse 0,0.0.127 Liberty
MatchCollection theMatches =
theReg.Matches( stringl );
Pogledajmo kako je ovaj red analiziran. Prevoditelj poinje s traenjem kolekcije krozkoju
e iterirati. theMatch je objekt koji sadri kolekciju Groups. Kolekcija Groups ima indekser
koji uzima niz i vraa jedan objekt Group. Stoga sljedei red vraa jedan objekt Group:
theMatch.Groups["company"]
Objekt Group ima kolekciju Captures. Stoga sljedei red vraa kolekciju Group za objekt
Group spremljen u Groups["company''] unutar objekta theMatch:
theMatch.Groups["company"].Captures
Petlja foreach prolazi kolekciju Captures i izdvaja svaki element te ga dodjeljuje lokal-
noj varijabli cap koja je tipa Capture. U izlazu moete vidjeti kako postoje dva elementa
za uzimanje: Desse i Liberty. Drugi element prepisuje prvi u grupi, te se prikazuje
samo vrijednost Liberty. Ako, meutim, pogledate kolekciju Captures, moete vidjeti
kako su uzete obje vrijednosti.
244 | Programiranje C#
Obrada i;
$i na kojem se oekuje slovo. Korisnika pogreka takoer moe izbaciti iznimku, ali
to moete sprijeiti hvatanjem pogreaka s pomou koda za provjeru valjanosti. Kori-
m snike pogreke bi se trebale predvidjeti i sprijeiti kad god je to mogue.
8s
Metoda za obradu iznimki (engl. exception handler) je blok koda projektiran za obradu
izbaene iznimke. Metode za obradu iznimki implementiraju se kao iskazi catch. U ide-
alnim uvjetima, ako je iznimka uhvaena i obraena, program moe ispraviti problem
i nastaviti s radom. ak i ako program ne moe nastaviti s radom, hvatanjem iznimke
omoguava se ispis smislene poruke o pogreci i prikladno zatvaranje programa.
Ako u metodi postoji kod koji se mora izvoditi bez obzira na izbacivanje iznimke (npr
radi oslobaanja dodijeljenih resursa), taj kod moete staviti u blok finally unutar '
kojeg e on sigurno biti pokrenut, ak i ako doe do iznimke.
Iskaz throw
Kako bi se u C # klasi objavila neuobiajena situacija, izbacuje se iznimka. Za to se
koristi kljuna rije throw. Sljedei red koda stvara novu instancu System.Exception i
zatim je izbacuje:
throw new System.Exception();
Izbacivanje iznimke odmah zaustavlja izvedbu, a CLR trai metodu za obradu iznimki.
Ako se metoda za obradu iznimki ne moe pronai u tekuoj metodi, izvedbeni okoli
odmotava stog i provjerava pozivajue metode sve dok ne pronae metodu za obradu
iznimki. Ako se stog odmota sve do Main(), a metoda za obradu iznimki nije prona-
ena, program se zatvara. To je prikazano u primjeru 11-1.
246 | Programiranje C#
primjer 11-1- Izbacivanje iznimke (nastavak)
Func2();
Console,WxiteLine("Exit Funcl...")
>?! }
-I ^k pridsnete View Detail prikazat e se pojedinosti iznimke koja nije obraena (slika
I f Vaj iednostavan Primjer na konzoli ispisuje svaki ulaz i izlaz iz metode. Metoda
t Main(J) StVara mstancu tipa Test i poziva Funci(). Nakon ispisa poruke Enter Funcl
metoda Funcl odm ah poziva Func2 (). Func2 ispisuje prvu poruku i izbacuje objekt tipa
j System.Exception. v
Exceptlon Snapshot:
a i
BiExceptton {"Exception of type 'System.Exception' was thrown."} ~~
s.?0 Data i{System.Collections.UstDictionaryInternal}
HelpLink nuli
S lnnerException nuli
Message Exception of type 'System.Exception' vvas thrown.
Non-Public members
' Source i ThrowingAnException
OK
S l i k a 11-2. P o j e d i n o s t i i z n i m k e
Iskaz catch
Metoda za obradu iznimki se u C # naziva blok za hvatanje i stvara se s pomou
kljune rijei catch. :|
U primjeru 11-2 iskaz throw se izvodi unutar bloka try , a blok catch obavjetava kako J
je iznimka obraena. |
P r im j e r 1 1 -2 . H v a t a n j e i z n im k e
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace CatchingAnException
{
public class Test
{
public static void Main()
{
Console.WriteLine( "Enter Main.. ) ;
Test t = new Test();
t.Funcl();
Console.WriteLine( "Exit Main..." );
243 | Programiranje C#
i_imj e r U -2 . H vatanje iznim ke (nastavak)
}
public void Funcl()
try
{
Console.WriteLine( "Entering try block..." );
throw new 5ystem.Exception();
Console.Writeline( "Exiting try block..." );
}
catch
{
Console.WriteLine(
4( "Exception caught and handled." );
vi' ; }
i Console.WriteLine( "Exit Func2 ..." );
}
I'
primjer 11-2 gotovo je identian primjeru 11-1, razlikuje se samo po tome to sadri i
blok try/catch. Blok try se obino stavlja oko potencijalno opasnog" iskaza, na pri-
fjnjer onog za pristup datoteci, dodjelu velikog prostora u memoriji i slino.
f za iskaza try nalazi se generiki iskaz catch. Iskaz catch iz primjera 11-2 je generiki
er nije odreeno kakve tipove iznimki treba hvatati. U ovom e sluaju iskaz hvatati
;vc izbaene iznimke. Koritenje iskaza catch za hvatanje odreenih tipova iznimki
objanjeno je kasnije u ovom poglavlju.
P r im je r 1 1 -3 . H v a t a n je u p o z i v n o j m e t o d i
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace CatchingExceptionInCallingFunc
{
public class Test
{
public static void Main()
try
250 | P ro g ra m ira n je C#
! p rim jer 11-3. H v a t a n je u p o z i v n o j m e t o d i ( n a s t a v a k )
Bitno je da razumijete zato se iskaz Exiting Try Block i Exit Func2 ne ispisuju. Ovo
je klasian ptimjer u kojem smjetanje koda u program za ispravljanje pogreaka i pro-
lazak kroz njega mogu pojasniti stvari.
P rim jer 1 1 -4 . Z a d a v a n j e iz n im k e z a h v a t a n je
using System;
. using System.Collections.Generic;
: using System.Text;
(tendregion
namespace SpecifyingCaughtException
a, b, DoDivide( a, b ) );
}
// Prvo ide tip najee izvoene iznimke
catch ( System.DivideByZeroException )
Console.Writetine(
"DivideByZeroException caught! );
catch ( 5ystem.ArithmeticException )
Console.Writetine(
"ArithmeticException caught!' );
}
// Generiki tip iznimke je zadnji
catch
Console.WriteLine(
Unknown exception caught" );
}
}
// Dijeli ako je dozvoljeno I
public double DoDivide( double a, double b ) i
3
{ I
if ( b == 0 )
throw new System.DivideByZeroException(),
252 | Programiranje C#
i
aj se iznimka izbaci, izvedbeni okoli redom provjerava sve metode za obradu
nki i odabire prvu odgovarajuu. Kad program pokrenete s a=5 i b=7, generirat
Je se sljedei izlaz:
5 / 7 = 0.7142857142857143
skazfinally
nekim instancama izbacivanje iznimke i odmotavanje stoga moe uzrokovati pro-
em. Ako ste, na primjer, otvorili datoteku ili na drugi nain zauzimate resurs, moe
m zatrebati mogunost zatvaranja datoteke ili pranjenja privremene memorije.
*ko postoji akcija koju morate izvesti bez obzira na izbacivanje iznimke (na pri-
mjer, ako trebate zatvoriti datoteku), moete izabrati izmeu dvije strategije. Moete
I
Primjer 11-5. Koritenje bloka finally
(tregion Us in g d ire ctiv es
using System;
using S y s t e m .C o l l e c t i o n s .Ge n e r i c ;
using System .Tex t;
Se ndregion
{
Test t = n ew Test();
t.TestFuncO;
}
// Poku ava po dij eliti dva broja i
// ob r auje mogue iznimke
public void Test Func ()
{
try
}
H Prvo ide tip najee izvoene iznimke
Ako iznimku izbacite iz bloka fmally, nije sigurno da e blok fmally dovriti izvoenje.
254 | Programiranje C#
primjer 11 5. Koritenje bloka finally (nastavak)
c a tc h ( S y s t e m . D i v id e B y Z e r o E x c e p t io n )
Console.WriteLine(
"DivideByZeroException caught!" );
i catch
{
Console.WriteLine( "Unknown exception caught" );
finally
{
Console.WriteLine( "Close file here." );
l. }
pObjekti Exception
Jg o sa d smo iznimke koristili kao osiguranje- to jest, postojanje iznimke oznaavalo
! h k PT c 3 1 3 S nlSm pnstuPlh lznlmci niti pregledali sam objekt Exception
g b je k t System. Exception prua razne korisne metode i svojstva. Svojstvo Message daje
iJ E
l t
aC1,e 1ZJ ,
nimC1 "aPnmjerraz,g nJeng izbacivanja. Svojstvo Message moe se
" kod koB Je Izbacl iznimku moe svojstvo Message postaviti kao argument
sl l f 0nstrUlktora iznimke.
using System;
using System.Collections.Generic;
using System.Text;
Sendregion
namespace ExceptionObject
{
public class Test
{
public static void Main()
{
Test t = new Test();
t.TestFunc();
}
// Pokuava podijeliti dva broja
// i obrauje mogue iznimke
public void TestFunc()
{
try
{
Console.WriteLine( "Open file here" );
double a = 1 2 ;
. double b = 0;
Console.WriteLine( "{} / {l} = {2}'',
a, b, OoOividej a, b ) );
Console.WriteLine(
"This line may or may not print" );
}
256 | Programiranje C#
rimjer 11-6. Rad s objektom Exception (nastavak)
catch ( System.DivideByZeroException e )
Console.WriteLine(
"\nDivideByZeroException! Msg: {o}".
e.Message );
Console. WriteLine(
"knHelpLink: {o}", e.HelpLink );
Console.WriteLine(
"inHere's a stack trae: {0}\n",
e.StackTrace );
}
catch (System.Exception e)
Console.WriteLine(
"Unknown exception caught + e.Message );
finally
{
Console.WriteLine(
"Close file here." );
if ( b == o )
{
Divide8yZexoException e =
new DivideByZeroException();
e.HelpLink =
"http://www.libertyassociates.com";
throw e;
}
if ( a == o )
throw new ArithmeticException();
return a / b;
f e a g u stogu koji se vidi u izlazu popisuje sve metode redoslijedom obrnutim od redo-
1 ; e 3 P zlvanja tj. u tragu se vidi kako se pogreka pojavila u metodi DoDivide() koju
^ je pozvala metoda TestFunc(). Kad su metode duboko ugnijeene, trag u stogu vam
||moze pomoi u razumijevanju redoslijeda pozivanja metoda.
Prilagoene iznimke
Ugraeni tipovi iznimki koje CLR prua, zajedno s prilagoenim porukama prika-
zanim u prethodnom primjeru, bit e vam dovoljni za pruanje dovoljno detaljnih
informacija catch bloku.
Ponekad e vam, meutim, biti potrebne zasebne metode za obradu iznimki ovisno o
uzroku iznimke. Za to ete morati stvoriti vlastite prilagoene tipove iznimki (stoga
moete stvoriti i zasebne metode za obradu iznimki). Prilagoeni tipovi iznimki mogu
dodati vi? informacija ili sposobnosti, no glavni je razlog postojanje drugaijeg tipa
kojeg blok catch moe razlikovati.
258 | Programiranje C#
jednostavno je potrebno stvoriti vlastitu klasu prilagoene iznimke. Jedino je oerani-
enj da ona mora izvoditi (izravno ili neizravno) iz System.ApplicationException. U
primjeru 11-7 prikazano je stvaranje prilagoene iznimke.
using System;
using S y s t e m .C o l l e c t i o n s .C e n e r i c ;
using System.Text;
tfendregion
namespace CustomExceptions
{
public class MyCustomException :
System.ApplicationException
{
public MyCustomException( string message ):
base(message)
{
}
}
try
{
Console.WriteLine( "Open file here );
double a = 0 ;
double b = 5 ;
Console.WriteLine( "{oj / {i} = { 2 }",
a, b, DoDivie( a, b ) );
Console.WriteLine(
"This line may or may not print" );
Console.WriteLine(
"\nDivideByZeroException! Msg: {o},
260 | Programiranje C#
joputen. Umjesto prilagoene iznimke moe se koristiti i ArithmeticException, no
|o bi moglo zbuniti druge programere jer se djelitelj nula obino ne smatra aritmeti-
Jkom pogrekom.
Kakoje InnerException takoer iznimka, i ona moe imati unutarnju iznimku. Stoga se
| cijeli lanac iznimki moe ugnijezditi unutar drugog lance, kao to se figurice babuke
% stavljaju jedna u drugu. To je prikazano u primjeru 11-8.
Hj.using ystem;
using System.Collections.Generic;
P.using System.Text;
'
||'#endregion
namespace RethrowingExceptions
{
public class MyCustomException : System.ApplicationException
Public MyCustomException(
string message, Exception inner ):
base(message,inner)
{
262 | Programiranje C#
11-7. Stvaranje prilagoene iznimke (nastavak)
try
{
DangerousFunc3();
}
.i // Ako uhvati DivideByZeroException poduzima
s
is t
// korektivne akcije i izbacuje ope iznimke
catch ( System.DivideByZeroException e )
t
Exception ex =
new Exception(
"E2 - func2 caught divide by zero", e );
throw ex;
}
}
catch ( 5ystem.Exception )
Console.WriteLine(
"Exception handled here." );
' }
}
}
}
Kakoje kod sveden na osnovne elemente, izlaz moe biti pomalo nejasan. Najbolji nain
za razumijevanje ovog koda je propustiti ga kroz alat za ispravljanje pogreaka.
Ponite pozivanjem metbde DangerousFunci() u bloku try:
try
{
DangerousFuncl();
264 1 Programiranje C#
Mjesto toga moete i za iznimku pozvati metodu ToString():
Console.Write(e.ToStringO);
Kada umre neki dravnik, predsjednik Sjedinjenih Amerikih Drava obino nema
dovoljno vremena da osobno ode na pogreb. On e stoga na pogreb poslati delegata.
Taj delegat je esto potpredsjednik, no ako ni potpredsjednik nije u mogunosti otii na
pogreb, predsjednik mora poslati nekog drugog, na primjer ministra vanjskih
poslova ili ak prvu damu. On ovlatenje delegata nee vrsto povezati sa samo jed-
nom osobom kako bi ga mogao dodijeliti bilo kojoj osobi koja je sposobna dobro oba- f
viti meunarodni protokol.
Predsjednik unaprijed definira koje e se ovlatenje dodijeliti (odlazak na pogreb), koji n
e se parametri prenijeti (suut, ljubazne rijei) te kojoj se povratnoj vrijednosti nada |
(dobra volja). On zatim ovlatenje dodjeljuje odreenoj osobi u prikladnom trenutku j
dok traje njegov mandat.
1
U programiranju se esto suoavamo sa situacijama u kojima je potrebno izvesti odre- >
enu akciju ali se ne zna unaprijed koja e se metoda ili objekt pozvati na izvoenje. /
Na primjer, gumb moe znati kako treba obavijestiti objekt da je pritisnut, ali moda : i
ne zna koji objekt ili objekte treba obavijestiti. Umjesto da gumb poveete s odreenim
objektom, povezat ete ga s delegatom i zatim tog delegata pri izvoenju programa j
dodijeliti odreenoj metodi. i.
U ranim, mranim i primitivnim danima programiranja, programi bi poeli izvoenje
i zatim prolazili kroz sve korake do kraja. Ako je korisnik bio ukljuen u proces, inter-
akcija je bila strogo kontrolirana i ograniena na popunjavanje polja.
Za dananji model programiranja s grafikim korisnikim sueljem potreban je druga-
iji pristup, poznatiji kao programiranje temeljeno na dogaajima (engl. event driven
programjning). Moderni program prikazuje korisniko suelje i eka na akciju kori-
snika. Korisnik moe izvesti vie razliitih akcija, poput odabira opcije iz izbornika,
pritiska na gumb, osvjeavanja tekstualnih polja, pritiska na ikonu i tako dalje. Svaka
akcija izaziva dogaaj. Drugi se dogaaji mogu izazvati bez izravne akcije korisnika.
Takvi su, na primjer, dogaaji koji odgovaraju na otkucaj unutarnjeg sata, prijem
poruke elektronike pote, dovretak operacije kopiranja datoteke itd.
266
Jp| j dogaaj je uahurena zamisao da se dogodilo neto na to program mora odgo-
v o r i t i . Dogaaji i delegati su usko povezani koncepti jer je za fleksibilno upravljanje
dogaajima potrebno da se odgovor na dogaaj otpremi do odgovarajue metode za
Slpbradu dogaaja. Metoda za obradu dogaaja se u C# najee implementira preko
feelegata.
Bpelegati se koriste i kao povratni pozivi kako bi jedna klasa drugoj mogla rei uini
'dvo i obavijesti me kad si gotova".
^ Delegati
Delegati (engl. delegates) su u C# objekti prve klase i za njih postoji potpuna podrka
u jeziku. Delegat je tehniki referentni tip koji se koristi za uahurivanje metode s
' odreenim potpisom i povratnim tipom.- U delegata se moe uahuriti bilo koja odgo-
u varajua metoda
Delegat se stvara s pomou kljune rijei delegate iza koje se navodi povratni tip i pot-
pis metoda koje mu se mogu delegirati, kao u sljedeem primjeru:
public delegate int WhichIsFirst(object objl, object obj2);
Ovom se deklaracijom definira delegat WhichIsFirst koji e uahuriti bilo koju metodu
koja kao parametre uzima dva objekta i vraa tip int.
;Nakon definiranja delegata u njega moete uahuriti metodu lanicu tako to ete ga
; instancirati prosljeivanjem metode koja odgovara navedenom povratnom tipu i pot-
pisu. Moete koristiti i anonimne metode, kao to je opisano kasnije. U oba se sluaja
delegat moe koristiti za pozivanje uahurene metode.
Razliiti e se objekti razliito sortirati (na primjer, par objekata Counter moe se sor-
i ttrati brojanim redoslijedom, dok se par objekata Button moe sortirati abecednim
U ovoj je definiciji delegat WhichIsFirst definiran tako da uahuruje metodu koja kao
parametre prima dva objekta i vraa objekt tipa Comparison. Comparison je enumeracija
koju ete definirati kao:
public enum Comparison
{
theFirstComesFirst = 1 ,
theSecondComesFirst = 2
}
Kako bi isprobali delegata, stvorit ete dvije klase: Dog i Student. One nemaju ba
mnogo zajednikih karakteristika, osim to obje implementiraju metode koje moe
uahuriti delegat WhichIsFirst, stoga su i objekti Dog i objekti Student prihvatljivi za
spremanje unutar objekata Pair.
U probnom programu stvorit ete nekoliko objekata Student i nekoliko objekata Dog te
ih sve spremiti u Pair. Zatim ete stvoriti instance WhichIsFirst kako biste uahurili
odgovarajue metode koje e odrediti redoslijed objekata Student i Dog. Promotrimo
ovaj postupak korak po korak.
Poinjete sa stvaranjem konstruktora Pair koji uzima dva objekta i sprema ih u pri-
vatno polje:
public Pair(
T firstObject,
T secondObject )
{
thePair[o] = firstObject;
thePairfl] = secondObject;
}
Zatim preoptereujete metodu ToStringO kako biste dobili vrijednost niza dva
objekta:
268 | Programiranje C#
public override string ToString()
}
cada unutar objekta Pair postoje dva objekta ije vrijednosti moete ispisati. Spremni
% za sortiranje i ispis rezultata sortiranja. Ne moete unaprijed znati o kakvim se
.|bjektima radi pa ovlatenje za odreivanje redoslijeda objekata delegirate samim
Objektima.
Jpase Dog i Student implementiraju metode koje delegat MhichlsFirst moe uahu-
| lti. Tijekom izvoenja ovaj delegat moe uahuriti bilo koju metoda koja uzima dva
.objekta i vraa tip Comparison.
3P T temp = thePairfo];
thePair[o] = thePairfl];
*=; thePair[i] = temp;
}
^Ova metoda prihvaa parametar: delegat tipa WhichIsFirst pod imenom theDelega-
jedFunc. Metoda Sort() ovlatenje za odreivanje redoslijeda objekta u Pair delegira
Cje analogno funkcioniranju ostalih parametara. Ako imate metodu koja kao para-
jjhetar uzima int:
int SomeHethod (int myParam){//...}
-|fiaziv parametra je myParam, no proslijeditise moe bilo koja int vrijednost ili varijabla.
|Shno tome, parametar u primjeru delegata ima ime theDelegatedFunc, no proslijediti
|se moe bilo koja metoda ija povratna vrijednost i potpis odgovarju onima definira-
-nim u delegatu WhichIsFirst.
^Pretpostavimo da objekte Student elite sortirati prema nazivu. Ako elite da na prvom
mjestu bude ima prvog studenta, napiite metodu koja vraa vrijednost theFirstComes -
. First, a ako elite da na prvom mjestu bude ime drugog studenta, napiite metodu koja
jVraa vrijednost theSecondComesFirst. Ako proslijedite ,,Amy, Beth, metoda vraa
-|theFirstComesFirst, a ako proslijedite Beth, Amy, ona vraa theSecondComesFirst.
if (theDelegatedFunc(thePair[0], thePairjlj) ==
Comparison.theFirstComesFirst)
{
T temp = thePairjo);
thePairjO] = thePair[l];
thePair[l] = temp;
}
Logika je ista kao kod metode S o rt(), samo to ova metoda izvodi zamjenu ako delegi-1
rana metoda kae da prvi element dolazi na prvo mjesto. Budui da delegirana metoda|
misli kako prvi element dolazi na prvo mjesto i radi se o obrnutom redoslijedu, eljeni
rezultat je da se drugi element nalazi na prvom mjestu. Ako ovaj put proslijedite ,,Amy, ;
Beth, delegirana metoda vraa theFirstComesFirst (tj. Amy se treba nalaziti na prvom i
mjestu), o budui da se radi o obrnutom redoslijedu, dolazi do zamjene vrijednosni i
na prvom se mjestu nalazi Beth. To omoguava da koristite istu delegiranu metodu
kao kod metode S o rt(),b ez potrebe da objekt podrava metodu koja vraa vrijednost
sortiranu obrnutim redoslijedom.
Sada su vam potrebni jo samo objekti za sortiranje. Stvorit ete dvije nevjerojatno jed-
nostavne klase Student i Oog. Objektima Student prilikom stvaranja dodijelite imena:
public class Student
{
public Student(string name)
{
this.name = name;
}
Klasa Student zahtjeva dvije metode: prvu koja premouje metodu ToStringO i drugu
koja e se uahuriti kao delegirana metoda.
Student mora premostiti metodu ToStringO tako da u Pair ta metoda, koja poziva
ToStringO za sadrane objekte, ispravno funkcionira. Implementacijom se samo vraa
ime studenta (koje ve jest objekt niza):
public override string To Strin g O
{
return name;
} '
Student mora implementirati i metodu kojoj Pair. Sort() moe delegirati ovlatenje za
odreivanje redoslijeda objekata:
return (String.Compare(sl.name, s2.name) < 0 ?
Comparison.theFirstComesFirst :
Comparison.theSecondComesFirst);
270 | Programiranje C#
feletoda String.Compare() je metoda .NET kostura iz klase String koja usporeuje
|gjva niza i vraa vrijednost manje od nule ako je prvi manji, vee od nule ako je drugi
Jljiiz manji i nulu ako su nizovi jednaki. Ta je metoda detaljnije obraena u poglavlju
JpO. Obratite pozornost da primijenjena logika vraa theFirstComesFirst samo ako je
||prvi niz manji. Ako su nizovi jednaki ili je drugi niz vei, metoda vraa theSecond-
KtornesFirst.
Jtjetoda WhichStudentComesFirst() kao parametre uzima dva objekta i vraa tip Com-
Hjparison. Time je ona prikladna da bude Pair.WhichIsFirst delegirana metoda ijem
jgpotpisu i povratnoj vrijednost odgovara.
'Druga je klasa Dog. Objekte klase Dog poredat emo prema teini tako da se laki psi
g f nalaze ispred teih. Potpuna deklaracija klase Dog glasi:
public class Dog
{
public Dog(int weight)
{
this.weight=weight;
}
return weight.ToStringO;
. 1
private int weight;
: U primjeru 12-1 prikazan je cijeli program koji ilustrira nain pozivanja delegiranih
i metoda.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace Delegates
{
public enum Comparison
{
theFirstComesFirst = 1,
theSecondComesFirst = 2
}
// Deklaracija delegata
public delegate Comparison
WhichIsFirst( T objl, T obj2 );
272 | Programiranje C#
I
fimjer 12-1 Rads delegatima (nastavak)
I I koji zadaju objekti
public void ReverseSort(
KhichlsFirst theDelegatedFunc )
{
if ( theDelegatedFunc( thePair[o], thePair[l] ) ==
Comparison.theFirstComesFirst )
{
T temp = thePairjo];
thePair[o] = thePair[l];
thePair[l] = temp;
}
}
// Instancira delegate
Pair<Student>.WhichIsFirst theStudentDelegate =
new Pair<Student>.WhichIsFirst(
Student.UhichStudentComesFirst );
Pair<Dog>.WhichIsFirst theDogDelegate =
new Pair<Dog>.WhichIsFirst(
Dog.WhichDogComesFirst );
dogPair.Sort( theDogDelegate );
Console.WriteLine( "After Sort dogPair\t\t: {0}",
dogPair.ToStringO );
274 | Programiranje C#
r^nljer 1 2 - 1 . Rad s delegatima (nastavak)
dogPair.ReverseSort( theDogDelegate );
Console.WriteLine( "After ReverseSort dogPair\t: {o}",
dogPair.ToString() );
^ }
}
,Il0gram Test stvara dva objekta Student i dva objekta Dog koje zatim dodaje u kontej-
ierPair. Konstruktor student uzima string za ime studenta, a konstruktor dog uzima
?4int za teinu psa:
Student lesse = new Student( "lesse" );
% Student Stacey = new Student( "Stacey" );
Dog Milo = new Dog( 65 );
Dog Fred = new Dog( 12 );
4 to!
Pair<Student> studentPair = new Pair<Student>( lesse, 5tacey );
Pair<Dog> dogPair = new Pair<Dog>( Milo, Fred );
Console.WxiteLine( "studentPair\t\t\t: {o}",
studentPair.ToStringO );
Console.WriteLine( "dogPair\t\t\t\t: {o}",
dogPair.ToStringO );
Zatim se ispisuje sadraj dva kontejnera Pair kako bi se vidio redoslijed objekata. Izlaz
, je sljedei:
studentPair : Tesse, Stacey
dogPair : 65, 12
Kao to smo i oekivali, redoslijed objekata je isti kao i prilikom dodavanja u kontej-
, nere Pair. Zatim se instanciraju dva objekta delegata:
Pair<Student>.UhichlsFirst theStudentDelegate =
f- new Pair<Student>.WhichIsFirst(
Student.WhichStudentComesFirst );
Pair<Dog>.WhichIsFirst theDogDelegate =
new Pair<Dog>.WhichIsFirst(
Dog.whichDogComesFirst );
'/Delegati su sada objekti koji se mogu proslijediti metodama. Oni se prvo prosljeuju
^metodi Sort() objekta Pair, a zatim metodi ReverseSort(). Rezultati se ispisuju na
-konzoli:
After Sort studentPair : Tesse, Stacey
After ReverseSort studentPair : Stacey, lesse
After Sort dogPair : 12, 65
After ReverseSort dogPair : 65, 12
Statiki delegati
Primjeru 12-1 moe se zamjeriti to od pozivajue klase (u ovom sluaju Test) zahti-
jeva instanciranje delegata koji su potrebni za sortiranje objekata u Pair. Dobro bi bilo
kad bi se delegati mogli dobiti izravno iz klasa Student i Dog. To se moe postii tako
da se svakoj klasi da vlastiti statiki delegat. Student moete modificirati tako da joj
se doda:
public static readonly Pair<Student>.WhichIsFirst OrderStudents =
new Pair<Student>.WhichIsFirst( Student.HhichStudentComesFirst.);
Time se stvara statiko polje delegata samo za itanje pod nazivom OrderStudents.
<r,
Polje OrderStudents se kao polje samo za itanje nakon stvaranja vie
ne moe modificirati.
Ta dva delegata su sada statika polja unutar svojih klasa. Svaki je unutar klase pove-
zan s odgovarajuom metodom. Delegati se mogu pozvati bez deklariranja lokalne
instance delegata jednostavnim prosljeivanjem statikog delegata klase:
studentPair.Sort(Student.OrderStudents);
Console.WriteLine("After Sort studentpair\t\t: {o}",
studentPair.ToStringO);
studentPair.ReverseSort(Student.OrderStudents);
Console.WriteLine(''After ReverseSort studentPair\t: {0 }",
276 | Programiranje C#
studentPair.ToString());
dogPair.Sort(Dog.OrderDogs);
Console.WriteLine( "After Sort dogPair\t\t: fo}"
dogPair.ToString());
dogPair.ReverseSort(Dog.OrderDogs);
Console.WriteLine("After ReverseSort dogPair\f Col"
dogPair.ToStringO);
m 8 ,i b iS K polia k ih
get
{
return new Pair<Student>.WhichIsFirst( MhichStudentComesFirst );
}
}
Isto tako, statiko polje Dog zamijenite s:
public static Pair<Dog>.WhichIsFirst OrderDogs
get
{
I return new Pair<Dog>.WhichIsFirst( MhichDogComesFirst );
}
Dodjela delegata ostaje ista:
studentPair.Sort(Student.OrderStudents);
dogPair.Sort(Dog.OrderDogs);
Da bismo vidjeli kako se vieodredini delegati stvaraju i koriste proi emo kroz kom-
pletan primjer. U primjeru 12-2 stvorit ete klasu MyClassWithDelegate koja definira
delegat koji kao parametar uzima niz, a vraa void:
public delegate void StringDelegate(string s);
Zatim ete definirati klasu myImplementigClass koja sadri tri metode koje vraaju void
i kao parametar uzimaju niz: W riteString, LogString i TransmitString. Prva metoda
ispisuje niz na standardni izlaz, druga simulira zapisivanje u datoteku dnevnika, a
trea simulira slanje niza putem Interneta. Delegate instancirate kako bi pozvali odgo-
varajue metode:
Writer("String passed to Writer\n");
Logger("String passed to L o g g e r V ) ;
Transmitter("String passed to TransmitterNn");
Da biste vidjeli kako se delegati kombiniraju, stvorit ete jo jednu instancu dele-
gata:
MyClassWithDelegate.StringDelegate myMulticastDelegate;
278 | Programiranje C#
|f primjeru 12-2 prikazan je ovakav nain kombiniranja delegata.
jjjiing System;
psing System. Collections.Generic;
jiing System.Text;
^fendregion
'ISamespace MulticastDelegates
f.
- 4 : public class MyClassWithDelegate
j {
/ / Deklaracija delegata
public delegate void StringDelegate( string s );
280 | Programiranje C#
*ritnjer 22-2- Kombiniranje delegata (nastavak)
myMulticastDelegate(
"Third string passed to Collector" );
I j dijelu Test primjera 12-2 definiraju se instance delegata i pozivaju se prve tri (Idriter,
J^ogger i Transmitter). etvrtom se delegatu, myMulticastDelegate, zatim dodjeljuje
^kombinacija prva dva delegata. Taj se kombinirani delegat zatim poziva, to rezultira
|pozivanjem metoda oba delegata. Dodaje se trei delegat, a kad se pozove myMulticast-
Delegate, pozivaju se sve tri delegirane metode. Na kraju se uklanja Logger pa, kada se
ipozove myMulticastOelegate, pozivaju se samo dvije preostale metode.
Mo vieodredinih delegata moe se najbolje razumjeti na primjeru dogaaja, koji su
objanjeni u nastavku ovog poglavlja. Kad se dogodi dogaaj poput pritiska na gumba,
pridrueni vieodredini delegat moe pozvati seriju metoda za obradu dogaaja koje
e odgovoriti na taj dogaaj.
Dogaaji
Grafika korisnika suelja, kao to su operativni sustav Microsoft Windows ili pre-
glednik Weba, zahtijevaju da programi odgovaraju na dogaaje. Dogaaj (engl. event)
moe biti pritisak na gumb, odabir opcije iz izbornika, dovretak prijenosa datoteke
i tako dalje. Ukratko, dogodi se neto na to trebate odgovoriti. Redoslijed dogaaja
ne moe se predvidjeti. Sustav miruje do pojave dogaaja, a onda izvodi akciju za
obradu dogaaja.
U grafikim korisnikim sueljima bilo koji element moe pokrenuti dogaaj. Na pri-
mjer, kad pritisnete gumb moete pokrenuti dogaaj Click. Dodavanje elemenata na
padajui popis moe pokrenuti dogaaj ListChanged.
Druge klase e biti zainteresirane za odgovaranje na dogaaje. Nain njihova odgova-
ranja nije bitan klasi koja izaziva dogaaj. Gumb jednostavno kae Ja sam pritisnut",
a klase na to odgovaraju na prikladan nain.
Objavljivanje i pretplaivanje
U jeziku C# svaki objekt moe objaviti (engl. publish) skup dogaaja na koje se ostale
klase mogu pretplatiti (engl. subscribe). Kad klasa objavi dogaaj, sve pretplaene
klase se o tome obavjetavaju. Zahvaljujui ovom mehanizmu va objekt moe rei
Mogu vas obavijestiti o sljedeem", a druge se klase mogu pretplatiti i rei Da, oba-
vijestite me o najnovijim dogaanjima". Gumb prilikom pritiskanja moe obavijestiti
beskonano mnogo promatraa. Gumb se naziva izdavaem (engl. publisher) jer obja-
vljuje dogaaj Click, a druge se klase nazivaju pretplatnicima (engl. subscribers) jer su
pretplaeni na informacije o dogaaju Click.
Uzmimo kao sljedei primjer klasu Clock koja pretplatnike klase moe obavijestiti
svaki put kad se vrijeme promijeni za jednu sekundu. Klasa Clock moe biti odgovorna
i za prikaz vremena u korisnikom suelju, umjesto za pokretanje dogaaja, pa zato
se onda uope zamarati s delegatima? Ako se koristi idiom objavljivanja/pretplaiva-
nja, klasa Clock ne mora znati kako e se njene informacije koristiti. Veza izmeu pra-
enja vremena i prikaza tih informacija se tako prekida. Nadalje, prilikom pokretanja
dogaaja moe se obavijestiti beskonano mnogo klasa. Pretplaene klase ne moraju
znati kako Clock funkcionira, a Clock ne mora znati na koji e nain pretplaene klase
odgovoriti na dogaaj.
Delegat, dakle, prekida vezu izmeu izdavaa i pretplatnika. To je vrlo poeljno jer
kod ini fleksibilnijim i robusnijim. Klasa Clock moe promijeniti nain detektiranja
vremena bez razbijanja pretplatnikih klasa. Pretplatnike klase mogu promijeniti
nain odgovaranja na vremenske promjene bez razbijanja klase Clock. Klase su pot-
puno neovisne jedna o drugoj, to kod ini jednostavnijim za odravanje.
Dogaaji i delegati
Dogaaji se u C # implementiraju s delegatima. Klasa izdava definira delegat, a pret-
platnika klasa ima dvije metode: prvo stvara metodu koja odgovara potpisu delegata,
a zatim stvara instancu tipa tog delegata uahurujui metodu. Prilikom pokretanja
dogaaja metode pretplatnike klase pozivaju se preko delegata.
Metoda koja obrauje dogaaj naziva se metoda za obradu dogaaja (engl. event han-
dler ). Metode za obradu dogaaja moete deklarirati na isti nain kao i ostale dele-
gate.
Metode za obradu dogaaja u .N ET kosturu obino vraaju void i uzimaju dva para-
metra. Prvi je parametar izvor" dogaaja (to jest, objekt izdava). Drugi je parame-
tar objekt izveden iz EventArgs. Metode za obradu dogaaja preporuljivo je stvarati
prema ovom uzorku.
a*
Napomena za VB6 programere: u C # ne postavlja ogranienja za imena
metoda koje obrauju dogaaje. .N ET implementacija modela objavlji-
vanja/pretplaivanja omoguava vam da imate jednu metodu koja je
pretplaena na razliite dogaaje.
282 | P ro g ra m ira n je C#
EventArgs je o sn o v n a kla sa za sve p o da tke do ga aja. K lasa EventArgs sve m eto de, osim
svog k o n stru k to ra , n aslje u je od k la se O b je ct, ali im a i ja v n o sta ti k o p olje empty koje
predstavlja doga aj bez sta n ja (k a k o bi se d oga aji b e z sta n ja u in k o v ito k o ristili).
Klasa izvedena iz EventArgs sadr i in fo rm a cije o dogaaju .
this.hour = hour;
*' this.minute = minute;
this. second = second;
% >
'p public readonly int hour;
p public readonly int minute;
public readonly int second;
& }
I
Ii Objekt TimelnfoEventArgs sadrat e informacije o trenutnom satu, minuti i sekundi.
H On definira konstruktor i tri javne cjelobrojne varijable samo za itanje.
3? Klasa Clock osim delegata sadri i tri varijable lanice - hour, minute i second - te jednu
y metodu Run():
* public void Run()
{
fr(;;)
{
// Spava 1 0 milisekundi
Thread.Sleep(lo);
ffj
I:
Poglavlje 12; Delegati i dogaaji | 283
{
// Stvara objekt TimelnfoEventArgs
// za prosljeivanje pretplatniku
TimelnfoEventArgs timelnformation =
new TimeInfoEventArgs(
dt .Hour,dt.Minute,dt.Second);
Prilikom otprilike svake stote provjere bit e dodana jedna sekunda. Metoda primje-
uje tu promjenu i obavjetava svoje pretplatnike. Kako bi to uinila, ona prvo stvara
novi objekt TimelnfoEventArgs:
if (dt.Second != second)
{
// Stvara objekt TimelnfoEventArgs
// za prosljeivanje pretplatnicima
TimelnfoEventArgs timelnformation =
new TimeInfoEventArgs(dt.Hour,dt.Minute,dt.Second);
284 | P ro g ra m ira n je C#
Ulomku koda moete vidjeti kako se referenca sata th is prosljeuje jer je sat izvor
'M jo samo treba stvoriti klase koje se mogu pretplatiti na ovaj dogaaj. Stvaraju se dvije.
Prva je klasa DisplayClock. Njen zadatak nije praenje vremena, ve prikaz trenutnog
f | vremena na konzoli.
}
Kad se pozove prva metoda, Subscribe (), ona stvara novi delegat SecondChangeHandler
prosljeujui metodu za obradu dogaaja TimeHasChanged(). Zatim tog delegata regi-
strira s dogaajem OnSecondChange od Clock.
Zatim se stvara druga klasa koja takoer odgovara na ovaj dogaaj - klasa LogCurrent-
0 Time. Ona obino slui za biljeenje dogaaja u datoteku, no u ovom primjeru dogaaj
se ispisuje na standardnu konzolu:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
#endregion
namespace EventsHithDelegates
{
// Klasa za uvanje informacija 0 dogaaju
// u ovom e sluaju uvati samo informacije
// dostupne u klasi clock, ali moe uvati i
// dodatne informacije 0 stanju
public tlass TimelnfoEventArgs : EventArgs
{
public TimelnfoEventArgs! int hour, int minute, int second )
{
this.hour = hour;
this.minute = minute;
this.second = second;
}
286 | Programiranje C#
Primjer 12-3. Implementacija dogaaja s delegatima (nastavak)
public readonly int hour;
p u b l i c i e a donly int m in u te;
public readonly int second;
}
object clock,
TimelnfoEventflrgs timelnformation
// Instanca delegata
public SecondChangeHandler OnSecondChange;
/ / Pokree sat
// objavit e dogaaj za svaku sekundu
public void Run()
{
for ( ; ; )
{
// Spava 1 0 milisekundi
Thread.Sleep( 1 0 );
OnSecondChange(
this, timelnformation );
)
I I Aurira stanje
this.second = dt.Second;
this.minute = dt.Minute;
this.hour = dt.Hour;
}
}
}
// Promatra. DisplayClock se pretplauje
// na dogaaje sata. Posao DisplayClock je
// da prikazuje trenutno vrijeme
public class DisplayClock
{
// Pretplauje se na dogaaj
// SecondChangeHandler sata
public void Subscribe( Clock theClock )
{
theClock.OnSecondChange +=
new Clock.SecondChangeHandler( TimeHasChanged );
}
}
// Ova bi metoda trebala zapisivati u datoteku.
// Ispisujemo na konzolu da bismo vidjeli efekt.
I I Ovaj objekt ne uva stanje,
public void WritelogEntry(
object theClock, TimelnfoEventArgs ti )
288 | Programiranje C#
'prim jer 1 2 -3 . I m p l e m e n t a c i j a d o g a a ja s d e l e g a t i m a ( n a s ta v a k )
}
}
public class Test
{
// Pravi no vi sat
Clock theC lock = new Clock();
// Po kre e sat
theClock.Run();
3 new C lock. Sec ond Chan geHa ndler(T imeH asCh anged) ;
}
Ako uinite tu malu promjenu, vidjet ete da se poziva metoda Logger(), ali ne i m etodi 5
DisplayClock . Operator dodjeljivanja je zamijenio delegata u vieodredinom delegatu!
OnSecondChange, a to nije dobro.
TimelnfoEventArgs timelnformation =
new TimelnfoEventArgs(
d t .Hour,d t .Minute,d t .Second);
theClock.OnSecondChange(theClock, timelnformation);
Metoda Main () je ovdje stvorila vlastiti objektTimelnf oEventArgs i izravno pozvala OnSe-
condChange. Ovaj kod dobro funkcionira, iako to nije bila namjera razvojnog inenjera
klase Clock. Izlaz je sljedei:
Calling the method directly!
Current Time: 18:36:7
Logging to file: 18:36:7
Current Time: 16:36:7
Logging to file: 16:36:7
u sljedeu definiciju:
290 | Programiranje C#
Jpublic event SecondChangeHandler OnSecondChange;
Idavanje kljune rijei event rijeit e oba problema. Klase se vie ne mogu na doga-
aj pretplatib preko operatora dodjele (-) kao to su to mogle ranije, niti mogu izravno
ozvati dogaaj, kao to je to uinila metoda Main() u prethodnom primjeru. Oba e
fjkuaja generirati pogreku u prevoenju:
The event 'Programming_CSharp.Clock.OnSecondChange' can only appear on
the left hand side of += or -= (except when used from within the type 'Programming_
CSharp.Clock')
M frim jer 1 2 -4 . K o r i t e n je k l ju n e r i je i e v e n t
Ipiising System;
Sfcusing System.Collect ions.Generic;
* using System.Text;
J$ using System.Threading;
;|j|'
||?#endregion
jinamespace EventKeyword
ll
// Klasa za uvanje informacija o dogaaju
/ / u ovom e sluaju uvati samo informacije
// dostupne u klasi clock, ali moe uvati i
// dodatne informacije o stanju
public class TimelnfoEventArgs : EventArgs
{
public readonly int hour;
public readonly int minute;
public readonly int second;
public TimeInfoEventArgs(int hour, int minute, int second)
{
this.hour = h o u r ;
this.minute = minute;
this.second = second;
}
}
// Pokree sat
// objavit e dogaaj za svaku sekundu
public void Run()
{
for(;;)
{
// Spava 10 milisekundi
Thread.Sleep(lO);
// Aurira stanje
this.second = dt.Second;
this.minute = dt.Minute;
this.hour = dt.Hour;
292 | Programiranje C#
%njer 1 2 - 4 . Koritenje kljune rijei event (nastavak)
}
}
r)
// promatra. DisplayClock se pretplauje
// na dogaaje sata. Posao DisplayClock je
i // da prikazuje trenutno vrijeme
.public class DisplayClock
{
// Stvara novi sat
Clock theCloc k = new Clock();
// Pokree sat
theClo ck.R un() ;
}
}
}
th eC lo ck .O nS ec on dC ha ng e +=
new Cl oc k. Se co nd C hange Han dler(Ti me Has Changed );
294 | Programiranje C#
ti.hour.ToStringO,
ti.minute.ToStringO,
ti.second.ToStiing() );
# ' vrijednost:
public class ClassHithDelegate
{
public delegate int DelegateThatReturnsInt();
public DelegateThatRetuinsInt theDelegate;
Kako biste to testirali, implementirajte dvije klase koje se pretplauju na delegat. Prva
uahuruje metodu koja poveava vrijednost brojaa i tu vrijednost vraa kao cjelo-
brojnu vrijednosti:
public class FirstSubscriber
{
private int myCounter = 0;
{ %
theClassWithDelegate.theDelegate += ?
new ClassWithDelegate.DelegateThatReturnsInt(Doubler); }:;
} j
public int Doubler() j
{
return myCounter += 2;
}
}
Kad se ovaj delegat pokrene, naizmjenino se pozivaju obje uahurene metode i svaka
vraa vrijednost:
int result = theDelegate();
Console.WriteLine(
"Delegates fired! Returned result: {o} ,
result);
Problem je u tome to svaka metoda vraa svoju vrijednost i prepisuje vrijednost koja
je dodijeljena objektu resu lt. Izlaz izgleda ovako:
Delegates fired! Returned result: 2
Delegates fired! Returned result: 4
Delegates fired! Returned result: 6
Delegates fired! Returned result: 8
Delegates fired! Returned result: 10
{
int result = del();
Console.WriteLine(
"Delegates fired! Returned result: {o}",
result);
}
Console.WriteLine();
296 | Programiranje C#
Delegates fired! Retur ned result: i
Delegates fired! R etu rned result: 2
Delegates fired! Re turn ed result: 2
Delegates fired! Returned result: 4
Delegates fired! Retur ned result: 3
Delegates fired! Retur ned result: 6
Delegates fired! Returned result: 4
Delegates fired! Retur ned result: 8
'Hi Delegates fired! Returned result: 5
_-l? Delegates fired! Returned result: 10
J|,Prva de,eglrana metoda odbr java ( . 1 2 , 3 , 4, 5), dok druga udvostruuje vrijednost (2 ,
>W 4 , 6 , 8 , 1 0 ). Cijeli je izvorni kod prikazan u primjeru 12-5.
f P rim jer 1 2 -5 . R u n o p o z i v a n j e d e le g ir a n ih m e t o d a
using System;
it using System.Collections.Generic;
using System.Text;
{jk using System.Threading;
#endregion
Vnamespace InvokingDelegatedMethodsManually
i if ( theDelegate != nuli )
{
// Eksplicitno poziva svaku delegiranu metodu
foreach (
DelegateThatReturnsInt del in
theDelegate.GetInvocationList() )
Console.WriteLine(
return myCounter += 2;
)
}
public class Test
298 | Programiranje C#
'Primjer 12-5. R u n o p o z i v a n je d e le g ir a n ih m e t o d a ( n a s t a v a k )
theClassWithDelegate.Run();
Evo kako to radi. Od delegata zatraite popis pozivanja i za svaki delegat s tog popisa
pozovite Beginlnvoke s dva parametra. Prvi e biti delegat tipa AsyncCallBack, a drugi *
e biti delegat koji poziva eljenu metodu:
del.BeginInvoke(new AsyncCallback(ResultsReturned),del);
U ovom redu koda poziva se metoda uahurena u del (to jest, DisplayCounter) i kad
metoda zavri, obavijest ete primiti preko metode ResultsReturned.
Metoda kojoj treba uzvratiti poziv (ResultsReturned) mora odgovarati povratnom tipu I i
potpisu delegata AsyncCallBack te mora vraati vrijednost void i uzimati objekt tipa i
IAsycResult: %
private void ResultsReturned(IAsyncResult iar)
{ I
Kad je metodi uzvraen poziv, .N ET kostur prosljeuje objekt IAsyncResult. Drugi |
parametar za Beginlnvoke je va delegat i on se sprema u svojstvo AsyncState suelja |
IAsyncResult kao Object. Unutar metode povratnog poziva ResultsReturned taj Object
moete izdvojiti i pretvoriti ga u njegov izvorni tip: |
DelegateThatReturnsInt del = (DelegateThatReturnsInt)iar.AsyncState; |
\
Sada taj delegat moete upotrijebiti za pozivanje metode EndInvoke(), prosljeujui |
primljeni objekt IAsyncResult kao parametar: |
int result = del.Endlnvoke(iar); |
Metoda EndInvoke() vraa vrijednost pozvane (i sada dovrene) metode koju dodjelju- J
jete lokalnoj varijabli result i koju sada slobodno moete prikazati korisniku. |
I
Ukupni efekt je da u metodi Run() naizmjenino dobivate registrirane metode (prvo !
FirstSubscriber.DisplayCounter, a zatim SecondSubscriber.Doubler) i svaku pozivate
asinkrono. Izmeu pozivanja prve i druge metode nema ekanja jer ne ekate da Dis-
playCounter vrati vrijednost.
Kad DisplayCounter (ili Doubler) ima rezultate, poziva se metoda povratnog poziva
(ResultsReturned) i koristite objekt IAsyncResult proslijeen kao parametar za uzima-
nje stvarnih vrijednosti. Cijela je implementacija prikazana u primjeru 12-6.
300 | Programiranje C#
bfifn jer 12- 6. A s i n k r o n o p o z i v a n j e d e l e g a t a
legion Using directives
jsing Systern;
jsin g System.Collections.Generic;
|ing System.Text;
jsing System.Threading;
jfendregion
jamespace AsynchDelegates
P'
public class ClassWithDelegate
if ( theDelegate != nuli )
// Poziva asinkrono i
// prosljeuje delegat kao objekt stanja
} I I kraj foreach
} I I kraj if
U kraj for ;;
H kraj run
// Prikazuje rezultate
Console.WriteLine( "Delegate returned result: {0 }", result );
3-
Poglavlje 12; Delegati i dogaaji | 301
P r im je r 1 2 - 6 . A s i n k r o n o p o z i v a n j e d e l e g a t a ( n a s t a v a k )
}
} // kraj class
theClassWithDelegate.Run();
}
}
}
302 | Programiranje C#
DIO II
Programiranje na jeziku C#
POGLAVLJE 13
T iTi L.-v,
L
ak i razlika u tome tko posjeduje korisniko suelje je donekle proiz-
voljna, poto suelja prikazana u pregledniku mogu imati komponente
koje se izvode lokalno, a samostalne aplikacije mogu imati ugraene
Web preglednike.
Ogromne su prednosti Web aplikacija. Moe im se pristupiti s pomou bilo kojeg pre
glednika koji se moe spojiti na posluitelj. Takoer, posluitelj se moe aurirati bezi
potrebe za dijeljenjem novih DLL-ova korisnicima. I
S druge strane, ako aplikacija nema koristi od pristupa Webu, mogue je postii veu -
kontrolu nad izgledom i uvidom u aplikaciju, odnosno mogue je postii bolju izvedbu
izradom samostalnih aplikacija. |
.N ET nudi blisko povezane, ali razliite skupove alata za programiranje Windows ili 1
Web aplikacija. Oba pristupa su temeljena na pretpostavci da mnoge aplikacije imaju 1
korisnika suelja koja s korisnikom komuniciraju preko obrazaca ili kontrola kao to 1
su gumbi, padajui popisi, tekst i tako dalje. M
Alati za izradu Web aplikacija se zovu Web Forms i razmatrani su u poglavlju 15. Alati 8
za izradu Windows aplikacija se zovu Windows Forms i tema su ovog poglavlja. ii
Na sljedeim stranicama ete nauiti kako izraditi Windows aplikaciju koristei Visual i
Studio. Ova aplikacija e obuhvatiti vei broj C# metoda koje su razmatrane u pret- |
hodnim poglavljima. i|
1
Izrada jednostavnog Windows Forms obrasca |
Windows Forms je alat za izradu Windows aplikacija. .N ET kostur nudi obimnu |
podrku za razvoj Windows aplikacija, iji je sredinji dio kostur za Windows obrasce. ^
Nije iznenaujue da Windows obrasci koriste metaforu obrasca. Ideja je posuena od 1
vrlo uspjene VB okoline i podrava brzi razvoj aplikacija. Premda je to diskutabilno, |
C# je prva okolina za razvoj koja je spojila alate za brzi razvoj iz VB okoline sa kvali- |
tetnim objektno orijentiranim karakteristikama obitelji C jezika. ;j|
i
Koritenje alata Visual Studio Designer |
Iako je mogue napraviti Windows aplikaciju koristei bilo koji editor (ak i Notepad!) J
i prevoenje iz naredbene linije, nerazumno je tako raditi kad Visual Studio.NET f
toliko olakava posao. is
|
Da biste poeli raditi novu Windows aplikaciju, prvo otvorite Visual Studio i odaberite |
File - New Project. U prozoru New Project napravite novu Windows aplikaciju i i
nazovite je ProgCSharpWindowsForm, kao to je prikazano na slici 13-1. j
Visual Studio odgovara izradom Windows Forms aplikacije i to je najbolje, postavlja j
vas u okoli za razvoj, kao to je prikazano na slici 13-2.
Prozor Design prikazuje prazan obrazac Formi. Dostupan je i prozor Toolbox sa
skupom gotovih Windows programa i kontrola. Ako prozor Toolbox nije prikazan,
pokuajte pritisnuti natpis Toolbox, ili odaberite View - Toolbox u Visual Studio
306 1 Programiranje C#
New Project
Project Type:
a VfcualC* _G 3g
_ _ V f s ^ S t u t t o jn s t a I le d te n p la te s
: Office
wm dow s
y3w
Cin
tesdLobw
rsA
v*acion
f
' a SiTidrj oevte trc* l b e r y
oatabase
W ndow s Con
ttt Other Languages
) e b C ontrct U bra y
ffl O ther Projec t Types
f
ons deAppfc aboo
ndow s Service
& n p t v Project
D lC nrsU l Peports w m dow s A ccfc a to n
E
Server Project
9 t PC 2003 A p p fc a t a i
et PC 2003 CJass U r * y
P o c k e t PC 2003 C m trd Ltr*y
f flP o c k e t PC 2003 C c rede A c pfc a t r
jg lP o c k e tP C 2003 Emp ty Project
i* je t t o o e a t iig an jpp i ao on w ith a W hdow s user h t e r t o e
i.'s s s s s B s s s s s s f u liM * - . **
P ro g C S h a r p W ir td o w s F o rm * M ic r o s o f t D e v e lo p m e n t E n v iro n m e n t
... Me*r Projeet 6trfd Oetug Data Toolj Vfttdan Help
Prije nego to nastavite, pogledajte okolo. Toolbox je ispunjen s kontrolama koje moete
dodati Windows Forms aplikaciji. U gornjem desnom kutu trebali biste vidjeti prozor
Solution Explorer koji prikazuje sve datoteke u projektu. U donjem desnom kutu se
nalazi prozor Properties koji prikazuje sva svojstva trenutno odabrane stavke. Na slici
13-3, odabran je natpis la b e ll i prozor Properties prikazuje njegova svojstva.
Moete koristiti prozor Properties da podesite svojstva raznih kontrola. Na primjer,
da biste dodali tekst natpisu la b e ll, moete upisati rijei Hello World u polje desno
od svojstva Text. Ako elite promijeniti pismo natpisa HelloVJorld pritisnite svojstvo
Font prikazano u donjem desnom kutu slike 13-4. (Takoer moete dodati tekst za
gumb buttonl tako to ete ga odabrati te u prozoru Properties upisati rije Cancel"
unutar njegova svojstva Text.)
Bilo koji od ovih koraka je esto laki nego mijenjanje ovih svojstava izravno u kodu
(iako je i to naravno mogue).
Kad je obrazac podeen, sve to preostaje je napraviti metodu za obradu pritiska na
gumb Cancel. Dvostruki pritisak na gumb Cancel e napraviti metodu za obradu doga-
aja, registrirati ju, i postaviti vas na stranicu koja sadri kod za obrazac, gdje moete
upisati logiku za upravljanje dogaajima kao to je prikazano na slici 13-5.
308 | Programiranje C#
*Prog CShai;p W lnd QwsFprm -M ic ro s o ft D e v e lp p m e n t E n v iro n m e n t " i ,-:v b
1F6 &Srt V froject bM Mu) CKATooHWNwtt>
1ifl*ijj*idf.kj 9 .
.A-J & *>i'*>'-> I.Cttu) *AnftfV a Ctvoftirost __
$X
.j..lT..^L..-i.Br.....S&ro'..tml;SoJfifpfjfififTOflffiiTiiffiflTIff
I
Kad pokuate upisati ovaj kod, alat Intellisense e vam pokuati pomoi. Kad upiete
A, bit e prikazano ime prvog objekta koji poinje sa A. Nastavite tipkati do Appl i
rf^r- U okoliu za razvoj ku rsor treperi, tako da je lake pratiti kod. Veini
itatelja ku rsor v jerojatn o nee treperiti u ovoj knjizi.
4'
Primjetite da datoteka s kodom (Form l.cs ) sadri samo naredbe using, konstruk-
tor i metodu za obradu dogaaja. Oni meu vama koji su programirali u prijanjim
inaicama jezika C# moda se pitaju gdje je ostatak koda za inicijaliziranje i postavlja-
nje svojstava kontrola (koje nisu navedene ovdje!). Primjetite da definicija klase sadri
kljunu rije p a rtia l. To ukazuje da se ostatak definicije klase nalazi u nekoj drugoj
datoteci. Ako pritisnete gumb Show Ali Files (zaokruen na slici 13-6), vidjet ete da
je Designer dodao drugu datoteku, Forml.Designer.es.
* Primjetite da Intellisense pamti va zadnji izbor i poinje s njim. Obino je to velika pogodnost.
310 | P ro g ra m ira n je C#
i^a potrebe ovog primjera te da biste kod bio jednostavan, fokusirajte se na korisniko
ljieelje i korake potrebne za povezivanje njegovih kontrola. Konaan izgled korisni-
7 suelja aplikacije je prikazan na slici 13-7.
* Fite Copier
ffl 0 AspBuUons
ffl 0 AspCalendat
WebApplication1 (2)
WmgDing$01 ii
i i ___________ lii a JJ r
Cleai 17] Ovemiite jf aasts
S li ka 13-7 . K o r i s n i k o s u e l j e a p l i k a c i j e F i l e C o p i e r
Cilj je omoguiti korisniku da pregleda datoteke (ili mape) u lijevoj (izvorinoj) kon-
troli za prikaz strukture mapa. Ako korisnik pritisne gumb Copy, datoteke oznaene
na lijevoj strani bit e kopirane u odredite odabrano na desnoj strani. Ako korisnik
pritisne Delete, oznaene datoteke e biti obrisane.
Ostatak ovog poglavlja opisuje nekoliko znaajki aplikacije FileCopier kako biste upo-
znali osnovne znaajke Windows Forms.
I
i
''.,5
312 | Programiranje C#
^ove metode za obradu jednostavnim upisivanjem novog imena ili odabirom neke od
postojeih metoda. Visual Studio registrira metodu za obradu dogaaja i otvara editor
Ikoda u kojem napravi zaglavlje i postavi kursor u prazno tijelo metode.
^Toliko to se tie jednostavnog dijela. Visual Studio generira kod za postavljanje obra-
sc a i inicijaliziranje svih kontrola, ali ne popunjava TreeView kontrole. To morate ui-
, iti runo.
Sada ste spremni napuniti kolekciju Nodes rekurzijom kroz sve mape svih diskova. Prvo
uzmite popis svih logikih diskova u sustavu. Da biste to uinili pozovite statiku
metodu GetLogicalDrives() objekta Environment. Klasa Environment prua tu informa-
ciju i pristupa trenutnoj okolini platforme. Moete koristiti Environment objekt da biste
saznali ime stroja, inaicu operativnog sustava, ime sistemske mape itd.
stringl] strDrives = Environment.GetLogicalDrives();
G etlogicalD rives() vraa polje nizova koji predstavljaju korijenske mape logikih
diskova. Iterirat ete unutar te kolekcije dodajui vorove kontroli TreeView.
foreach (string rootDirectoryName in strDrives)
{
Obradite svaki logiki disk s pomou foreach petlje.
Prvo to treba provjeriti jest da li je logiki disk spreman. Moj prijedlog za to je da
uzmete popis mapa najvie razine pozivanjem metode GetD irectories() na objektu
tipa DirectoryInfo koji sam napravio za korijensku mapu:
DirectoryInfo dir = new DirectoryInfo(rootDirectoryName);
dir.GetDirectories();
Da biste dobili znakove + desno u TreeView kontroli, morate pronai barem dvije
razine map'a (tako da TreeView kontrola zna koja mapa ima podmape i moe upi-
sati znak + pokraj njih). Ne elite prolaziti kroz sve podmape jer bi to bilo previe
sporo.
Posao metode GetSubDirectoryNodes() je da proe dve razine u dubinu, prosljeujui
korijenski vor, ime korijenske mape, zastavicu koja zadaje treba li traiti datoteke i
trenutnu razinu (uvijek poinjete na prvoj razini):
314 | Programiranje C#
if ( isSource )
{
GetSubDirectoryNodes(
ndRoot, ndRoot.Text, true,l );
}
else
{
GetSubDirectoryNodes(
ndRoot, ndRoot.Text, false,l );
}
Vjerojatno se pitate zato je potrebno proslijediti ndRoot.Text ako ve prosljeujete
ndRoot? Strpite se - vidjet ete zato je to potrebno kad se vratite u metodu GetSubDi-
rectoryNodes(). Sad ste zavrili s metodom FillD irectoryTree(). Pogledajte primjer
13-1 kasnije u ovom poglavlju za kompletan ispis ove metode.
Primjetite da proslijeeni vor ima ime parentNode. vorovi na trenutnoj razini e biti
potomci proslijeenog vora. Na ovaj nain preslikavate strukturu mapa na hijerarhiju
treeview kontrole.
Proite kroz sve podmape, preskaui one koji su oznaene kao Hidden:
foreach (DirectoryInfo dirSub in dirSubs)
{
if ( (dirSub.Attributes &
FileAttributes.Hidden) != o )
{
continue;
1
FileAttributes je enumeracije. Njene ostale mogue vrijednosti ukljuuju Archive,
Compressed, Directory, Encrypted, Hidden, Normal, ReadOnly, itd.
F ile ln fo klasa (opisana u poglavlju 21) pruae metode instance za rad s datotekama.
Sad moete proi kroz kolekciju pristupajui svojstvu Name objekta Fileln fo i prosli-
jediti ga konstruktoru TreeNode objekta, koji onda moete dodati u kolekciju Nodes
roditeljskog vora (tvorei tako vor-potomak). Ovaj put nema rekurzija jer datoteke
nemaju podmape:
316 | Programiranje C#
|!foreach (Filelnfo file in files)
' }
j je sve to je potrebno da biste popunili dva treeview objekta. Pogledajte primjer
14 za kompletan ispis ove metode.
SetCheck(e.Node,e.Node.Checked);
}
Za svaki TreeNode u kolekciji vorova provjerite da li predstavlja list (engl. leaf). vorje
list ako njegova kolekcija ne sadri nijedan vor. Ako je list, postavite njegovo svojstvo
Check na vrijednost koja je proslijeena kao parametar. Ako nije l i s t , ponovite:
private void SetCheck(TreeNode node, bool check)
{
// Trai sve vorove-potomke ovog vora
foreach (TreeNode n in node.Nodes)
{
n.Checked = check; // Odabira vor
irenje mape
Svaki put kad pritisnete znak + pored mape u izvorinoj (ili odredinoj) TreeView kon-
troli, elite proiriti mapu. Da biste proirili mapu trebate metodu za obradu dogaaja
318 | Programiranje C#
RforeExpand. Poto e te metode biti identine za izvorini i odredini TreeView objekt,
f c j a ete napraviti zajedniku metodu za obradu dogaaja za oba objekta:
private void tvwExpand(object sender, TreeViewCancelEventArgs e)
}
pn/i red ovog koda pretvara objekt koji je proslijedio delegat iz object u TreeView, to
|je sigurno poto znate da samo TreeView kontrola moe izazvati ovaj dogaaj.
IVa sljedei zadatak je da zadate elite li uzeti datoteke iz mape koju otvarate, a to
elite samo ako je ime objekta TreeView koji je izazvao ovaj dogaaj tvwSource.
Ispred kojeg vora je pritisnut znak + moete utvrditi uzimanjem svojstva Node od
iTreeVievtEventArgs objekta kojeg je dogaaj proslijedio:
TreeNode currentNode = e.Node;
^ Kad imate tekui vor znate njegovu punu putanju (koju ete trebati kao parametar
za GetSubDirectoryNodes) i onda morate oistiti njegovu kolekciju podvorova, poto
ete ju ponovno napuniti pozivanjem GetSubDirectoryNodes:
sSK': currentNode.Nodes.Clear () ;
J ? Zato brisati podvorove i onda ih ponovno dodavati? Jer ete ovaj put ii jo jednu
razinu u dubinu tako da podvorovi znaju ako i oni imaju podvorove te da biste posta-
vili znakove + pokraj njihovih podmapa.
Rekurzija prestaje kad vie nema roditeljskih vorova tj. kad doe do korijenskej
mape.
320 | Programiranje C#
Implementacija dogaaja gumba Copy
kad znate odabrati datoteke i odredinu mapu, spremni ste za obradu dogaaja
J|j'a korisnik pritisne gumb Copy. Prva stvar koju trebate uiniti je uzeti popis odabra-
l i datoteka. Ono to traite je polje Filelnfo objekata, ali ne znate koliko objekata
Jg.biti na popisu. To je pravi zadatak za ArrayList. Dodijelite zadau popunjavanja
metodi G etF ile List():
private void btnCopy_Click (
object sender, System.ventArgs e)
l i ja biste uzeli imena odabranih datoteka, moete proi kroz izvorinu TreeView kon-
fliolu:
foreach (TreeNode theNode in tvwSource.Nodes)
{
GetCheckedFiles(theNode, fileNames);
}
B )a biste vidjeli kako to funkcionira, uite u metodu GetCheckedFilesf). Ona je prilino
Jednostavna: ispituje vor koji joj je proslijeen. Ako taj vor nema potomaka (node.
Pddes.Count == o), onda je list. Ako je taj list odabran, uzmite punu putanju (poziva-
$jjemmetode GetParentString() za taj vor) i dodajte ju u parametar ArrayList:
private void GetCheckedFiles( TreeNode node,
List<string> fileNames )
1
// Ako je list...
if ( node.Nodes.Count == o )
{
// Ako je vor odabran...
if ( node.Checked )
{
// uzmite punu putanju i dodajte ju u arrayList
string fullPath = GetParentString( node );
fileNames.Add( fullPath );
}
}
if (file.Exists)
{
fileList.Add(file);
}
}
322 | Programiranje C#
Uobiajen pristup je da metoda vrati vrijednost 1 ako je prvi objekt (filel) vei od dru-
gog (file2), da vrati vrijednost -1 ako je istina suprotno, i da vrati vrijednost 0 ako su
objekti jednake veliine. U ovom sluaju, elite sortirati od veih prema manjima pa
biste trebali zamijeniti vrijednosti koje metoda vraa.
Da biste ispitali duljinu Filelnfo objekta morate pretvoriti parametre object u F ile-
Info objekte (to je u redu jer znate da ova metoda nikad nee primiti nita drugo):
if (filel.Length > file2,Length)
{
return -1;
i
if (filel.Length < file2.Length)
{
return l;
}
return 0;
}
}
Vratimo se metodi G etFile L ist() gdje ste se upravo spremali instancirati referencu
IComparer i proslijediti je metodi Sort() fileList:
IComparer<FileInfo> comparer = ( IComparer<FileInfo> ) new FileComparer();
fileList.Sort(comparer);
U ovom trenutku vratili ste sortirani popis F ile objekata od kojih svaki predstavlja
datoteku odabranu u izvorinoj TreeView kontroli.
Sad moete prolazei kroz popis kopirati datoteke i aurirati korisniko suelje:
foreach (Filelnfo file in fileList)
{
try
f
lblStatus.Text = "Copying " +
txtTargetDir.Text + "\\" +
file.CopyTo(txtTargetDir.Text + "\\"
file.Name,chkOverwrite.Checked);
}
Moete koristiti statiku metodu Show() iz MessageBox i proslijediti joj poruku koju
elite prikazati, naslov Delete F ile s kao niz znakova i zastavice kako slijedi:
MessageBox.OKCancel trai dva gumba: OK i Cancel.
MessageBox.IconExclamation govori da elite prikazati ikonu usklinika.
MessageBox.DefaultButton.Button2 postavlja drugi gumb (Cancel) kao podrazu-
mijevani izbor.
324 | Programiranje C#
ad korisnik pritisne OK ili Cancel rezultat se prosljeuje natrag kao enumerirana
pjijednost System.Windows.Forms.DialogResult. Moete provjeriti ovu vrijednost da
-vidite je li korisnik odabrao OK:
if (result == System.Windows.Forms.DialogResult.OK)
{
kko jest, moete dobiti popis imena datoteka fileNames i prolazei kroz njega brisati
jvaku od njih:
Arraylist fileNames = GetFileList();
iy
file.Delete();
}
: Ovaj kod je identian kodu za kopiranje osim to je metoda koju se poziva nad dato-
tekom Delete().
j using System;
i using System.Collections;
:using System.Collections.Generic;
- using System.ComponentModel;
using System.Data;
;; using System.Drawing;
using System.IO;
using System.Windows.Forms;
Hendregion
H I I I <remarks>
P !U File Copier - Windows Forms demonstracijski program
III (c) Copyright 2005 Liberty Associates, Ine.
U ! </remarks>
namespace FileCopier
{
III <summary>
III Obrazac za demonstraciju Windows Forms implementacije
I I I </summary>
partial class frmFileCopier : Form
{
private const int MaxLevel = 2;
public frmFileCopier()
{
InitializeComponent();
FillDirectoryTree( tvwSource, true );
FillDirectoryTree( tvwTarget, false );
}
III <summary>
III Ugnijeena klasa koja zna kako usporeivati
/// dvije datoteke koje elimo sortirati od vee prema manjoj.
I I I </summary>
public class FileComparer : IComparer<FileInfo>
{
public int Compare(FileInfo filel, Filelnfo file2)
{
if ( filel.Length > file.Length )
{
return -1;
326 | Programiranje C#
primjer 13-1. Izvorni kod FileCopier aplikacije (nastavak)
II Uzima logike diskove i stavlja ih
// u korijenske vorove. Popunjava polje s
// logikim diskovima na stroju.
string[] strDrives = Environment.GetLogicalDrives();
try
{
GetSubDirectoryNodes(
ndRoot, ndRoot.Text, true,l );
}
else
{
GetSubDirectoryNodes(
ndRoot, ndRoot.Text, false,l )
}
}
// Hvata pogreke poput
I I diska koji nije spreman,
catch
{
}
Application.DoEvents();
}
} // Z at v ar a FillSourceDirectoryTree
I I I <summary>
I I I Uzima sve podmape ispod
I I I proslijeenog vora mape.
I I I Dodaje ih u stablo mapa.
I I I Proslijeeni parametri su roditeljski vor
/// za tu podmapu,
I I I puna putanja podmape,
I I I i Boolean zastavicu koja govori
I I I da li treba uzeti datoteke iz podmape.
I I I </summary>
private void GetSubDirectoryNodes(
TreeNode parentNode, string fullName, bool getFileNames,
int level )
{
DirectoryInfo dir = new DirectoryInfo( fullName );
DirectoryInfo[] dirSubs = dir.GetDirectoriesO;
I I I <summa ry>
III Svaka mapa ima punu putanju.
III Trebamo ju podijeliti na kosim crtama,
III i upotrijebiti samo
III zadnji vor u stablu.
III Potrebno je dvaput napisati kosu crtu
/// jer je ona inae
III znak za prekid
I I I </summary>
TreeNode subNode = new TreeNode( dirSub.Name );
parentNode.Nodes.Add( subNode );
328 | Programiranje C#
mtimjer 13-1. Izvorni kod FileCopier aplikacije (nastavak)
I I Nakon spremanja vorova,
// sada sprema datoteke iz mapa.
foreach ( Filelnfo file in files )
{
TreeNode fileNode = new TreeNode( file.Name );
parentNode.Nodes.Add( fileNode );
}
}
I II <summary>
I II Pravi sortirani popis svih
I I I datoteka odabranih za kopiranje
III u odredinu mapu
I I I </summary>
private void btnCopy_Click( object sender,
System.EventArgs e )
{
// Uzima popis
l // Kopira datoteke
try
{
// Osvjeava natpis da prikazuje napredak
lblStatus.Text = "Copying " + txtTargetDir.Text
+ file.Name + "...
Application.DoEvents();
catch ( Exception ex )
{
I I Moda elite neto vie od
I I prikazivanja poruke
MessageBox.Show( ex.Message );
}
lblStatus.Text = "Done.";
Application.DoEvents();
I I I <summary>
III Govori korijenu svakog stabla da poniti
III odabir svih vorova ispod
I I I </summary>
}
}
I I I <summary>
III Ako korisnik pritisne Cancel zatvara se
I II </summary> _ .. .
private void btnCancel_Click(object sender, EventArgs e)
Application.Exit();
}
I I I <summary>
III S popisom i polje na raspolaganju
III popunjava popis imenima
III svih odabranih datoteka
I I I </summary>
// Popunjava ArrayList sa punim putanjama
// odabranih datoteka
private void GetCheckedFiles( TreeNode node,
List<string> -fileNames )
{
// Ako je list...
i-f ( node.Nodes.Count == 0 )
}
}
else // Ako ovaj vor nije list
GetCheckedFiles( n, fileNames );
}
}
I I I <summary>
III Uzima vor i vraa
III punu putanju
/// </summary>
330 | Programiranje C#
Primjer 13-1. Izvorni kod FileCopier aplikacije (nastavak)
private string GetParentString( TxeeNode node )
{
// Ako je ovo korijenski vor (c:\) vraa tekst
iF ( node.Parent == nuli )
{
return node.Text;
}
else
{
// Vraa se nagore i uzima putanju,
// zatim dodaje ovaj vor i kosu crtu
// Ako je ovaj vor list, ne dodaje kosu crtu
return GetParentString( node.Parent ) + node.Text +
( node.Nodes.Count == 0 ? : "\\" );
}
}
I I I <summary>
III Dijele ju operacije brisanja i kopiranja
III Stvara sortirani popis
III odabranih datoteka
I I I </summary>
private List<FileInfo> GetFileList()
{
// Stvara nesortirano polje punih putanja datoteka
List<string> FileNames = new List<string>();
I I I <summary>
III Provjerava de li korisnik zaista eli brisanje.
III Pravi popis i brie svaku datoteku.
I I I </summary>
private void btnDelete_Click( object sender, System.EventArgs e )
{
// Pita korisnika je li siguran
System.Windows.Forms.DialogResult result =
MessageBox.Show(
"Are you quite sure?", // Poruka
"Delete Files", // Natpis
MessageBoxButtons.OKCancel, // Gumbi
HessageBoxIcon.Exclamat ion, // Ikone
MessageBoxDefaultButton.Button2 ); // Podrazumijevani gumb
// Brisanje!
file.Delete();
}
catch ( Exception ex )
{
312 | Programiranje C#
primjer 13-1. Izvorni kod FileCopier aplikacije (nastavak)
I I Moda elite neto vie od
// prikazivanja poruke
MessageBox.Show( ex.Message );
}
}
lblStatus.Text = "Done.1;
Application.DoEvents();
}
}
I I I <summary>
III Uzima punu putanju odabrane mape
I II i kopira ju u txtTargetDir
I I I </summary>
private void tvwTargetDir_AtterSelect(
object sender,
System.Windows.Forms.TreeViewEventArgs e )
{
// Uzima punu putanju za odabranu mapu
string theFullPath = GetParentString( e.Node );
I I I <summary>
III Obiljeava svaki vor ispod tekueg
'III s trenutnom vrijednosti obiljeenog vora
I I I </summary>
private void tvwSource_AfterCheck( object sender,
System.Windows.Forms.TreeViewEventArgs e )
{
// Poziva metodu za rekurzivni prolaz.
// e.node je vor koji je korisnik odabrao.
// Stanje oznake za potvrdu je ve promijenjeno
// dok ste stiglo do ovog mjesta.
// Zbog toga elimo proslijediti
// stanje e.node.Checked.
if(e.Action != TreeViewAction.Unknown)
{
SetCheck(e.Node, e.Node.Checked );
}
I I I <summary>
/// rekurzivno postavlja ili brie oznake za potvrdu
I I I </summary>
Isti ishod moete postii u Visual Studiju pritiskom na ikonu projekta FileCopier u pro-
zoru Solution Explorer, odabirom opcije View Propery Pages u Visual Studio izborniku
i zatim odabirom opcije Build property page. Potvrdite polje XMLDocumentation File
i upiite ime X M L datoteke koju elite napraviti, na primjer FileCopier.XML.
Dio datoteke koja je napravljena za aplikaciju FileCopier iz prijanjih odlomaka je
prikazan u primjeru 13-2.
334 | Programiranje C#
13 -2 . O d l o m a k X M L d a t o t e k e s a d o k u m e n t a c i j o m z a a p l i k a c i j u z a k o p i r a n j e d a t o t e k a
lpm)er
fo
<assembly>
<name>FileCopier</name>
</assembly>
<members>
cmember name="T:FileCopier.frmFileCopier">
<summary>
Obrazac za demonstraciju Windows Forms implementacije
</summary>
</member>
cmember name="F:FileCopier.frmFileCopier.components">
<summary>
Required designer variable.
1 </summary>
</member>
j: cmember name="M:FileCopier.frmFileCopier.Dispose(5ystem.Boolean)>
- <summary>
Clean up any resources being used.
i </summary>
i </member>
cmember name="M:FileCopier.frmFileCopier.InitializeComponent">
<summary>
Required method for Designer support - do not modify
the contents of this method with the code editor.
</summary>
</member>
cmember name="M:FileCopier.frmFileCopier.GetSubDirectoryNodes
(System.Windows.Forms.TreeNode,System.String,System.Boolean,System.Int32)>
<summary>
Uzima sve podmape ispod
proslijeenog vora mape.
Dodaje ih u stablo mapa.
Proslijeeni parametri su roditeljski vor
za tu podmapu,
puna putanja podmape,
i Boolean zastavicu koja govori
da li treba uzeti datoteke iz podmape.
</summary>
</member>
cmember name="M:FileCopier.frmFileCopier.btnCopy_Click
(5ystem.Object,5ystem.EventArgs)">
<summary>
Pravi sortirani popis svih
datoteka odabranih za kopiranje
u odredinu mapu
</summary>
</member>
Dokument je velik, i iako je ljudima itljiv, nije previe koristan u tom obliku. Moete,
meutim, napisati XSLT datoteku da prevede XML u HTM L, ili moete uitati XML
dokument u bazu podataka za dokumentaciju. Takoer moete povui datoteku iz
1
<3x
<3xml vorsio
vorsion= l.Q* 1>
<ri'ime>F(leCoplorc/nsrne>
<ri'ime>F(leCoplorc/nsrne>
<assemb
embly>
</s
</ssen>bl
one
- on
n>bly>
c/tnembof>
- cmembers?
ember n am e='
e='T :F ll eCo
<summary5Forrn dem
eCopl er.frm Fl leCo
de m on str
eCopl er->
str o tln g Vll
Vl ln dow
dow s F orr
or r n s lmp
lmplem
lemenlj
enljr
ljr tlo
tlon</
n</5uin maiy>
s$1$
- <menienibet narn ee' ee 'F iFileC
leCopI
opIe r .frm FIleCleCoplople r.compoueni
ompoue nis nis *?
<sumrna
umrnarnary>Requlred d e sl gner ner v eHobl e.c /tu inm srv j
</rtember>
- cmember nai nain9*,M
*,M:F llelle Copl
op le r .fnnF
nn F lleC
le Copl
ople r .D ls p os e <S ysten steni
en i.Bo ol ean)
ean )* :
<su
<summ arv>Clean up o n y r e s ou r c e s bel bel n g used.<
used.</summary>
</member ber>
- <member ber name="
name="M :FJIeC Ie Copl
op le r .fr m Fll e Copl
op le r .I n l tlo ll z eC om poneni
onen i'>
<su
<summary>Requlrod m e t h od f o r De slg ner ne r su pport
pport - do n ot m odif od ifv
ifv th e con ten ts of th l s m e th o d
w r t h t b e c ade
ade edieditor .</sutnm% nm%rj>
c/member?
oii
oiiern
ernber n3me 3me=M :F l l e C o ple r .f r m F lleC o p le r .G e tSub0lrSub0 lre lr e c tory
or y N od o s
(8 y s te m .W l ndo w s .F o r m s .T r ee N ode /8y st e ro .8 t rln rl n g ,S y st e ro .B o o l e o n ,8 y s l e m .l n t 32 )',
)',>
<sumniary>Gets ell tb e subd ub dl re c tories
ories balova th e pe ss e d In d lre lr e c to r y no d e . Add s to th e d l re c toryor y
t r ee . T h e per
pe r e m e te r s p e ss e d In ere th e per pe re n t n ode od e fo r th l s s ubdlr
ubd lre
lr e c tory
or y , th e tuli pet
peth neni
neni e
of th l s s ubdlr
ubd lrs
lr s cto
cto r y , ond o Boolee ol een
ee n to In dlce te tvh eth er o r not to g e t th e fil fil es In the
su bdlr eotar tar y.</sum
summ ery ery>
</rnem
</rnember>ber>
- cmember name me M :F H e C o p l e r .fnn F l le Co p l e r .b tn Co p y_ C tl c k (S y st e m .O b J e ct/ ct/8 y st e m .e w en tA rg s ) , >
<sum
<sum marymary>Creo reote on o r der de r e d list of ell th e se l e c to d Hles, les, c o p y to th e to rg e t dlrect lrecto
ctor y<A unnnary>
unnnary>
</member ber>
cmember n s m e= 'M :F lleC op l er .f r m Flle ll ec o p te r .b tnC leo r_ C Hck( ck (S y ste
ste m .O b Je c t/f l y s t e m .even tA r g s )'>
)'>
<summar/>Tell th e r oot of oo c h tro e to un ch ock ell th e node nod e s belowc/
belowc/sururna rurnaiy>
</t
</tnembeo
- cmember nam na m e =*M
=* M :F l le C opl
op le r .f r m F ll e C opl
op le r .b tnC e n c e L c l le k ( Sy s te m .O b j e ct, ct,S y st e m .E ven tA r g s) * >
csuntm
untmar
tmary
ary>on cenc en c al , exltc/summ3rv>
</member ber>
<n)
<n)Bmber ber name=*M
name=*M :Flle lle Copl
opler .fm iF| le Cop Coplor .G etC h ecke dFlle lle s
S My Comput
puter
336 | Programiranje C#
_________________________ POGLAVLJEM
Pristup podacima kroz AD&NET
Mnoge aplikacije trebaju pristupati bazi podataka. .NET kostur prua irok skup obje-
kata za povezivanje s bazom podataka. Ove klase se nazivaju zajednikim imenom
ADO.NET.
ADO.NET izgleda vrlo slino kao ADO, njegov prethodnik. Kljuna razlika je da je
ADO.NET prirodni dio .NET kostura (nije samo omota za OLEDB) i da je to prven-
stveno nepovezana podatkovna arhitektura. U nepovezanoj arhitekturi podaci se uzi-
maju iz baze podataka i pohranjuju lokalno. Vi radite s tim podacima na lokalnom
raunalu i spajate se na bazu podataka samo kada elite promijeniti zapise ili uzeti
nove podatke.
Postoje znatne prednosti kod odvajanja podatkovne arhitekture od baze podataka. Naj-
vea prednost je da aplikacija, bilo da se izvodi na Webu ili lokalno, predstavlja manje
optereenje za posluitelj baze podataka, to aplikaciju moe uiniti prilagodljivijom.
Veze prema bazi podataka se intenzivno koriste i teko je odravati tisue (ili stotine
tisua) istovremenih veza. Nepovezana arhitektura omoguava utedu sredstava.
ADO.NET se spaja na bazu podataka da uzme podatke i zatim se ponovno spaja da
aurira podatke koje ste promijenili. Veina aplikacija provodi veinu vremena jed-
nostavno itajui podatke i prikazujui ih. ADO.N ET osigurava neovisni podskup
podataka koji ete koristiti za itanje i prikazivanja podataka.
337
Tablice, zapisi i stupci
Northvvind baza podataka opisuje izmiljenu tvrtku koja kupuje i prodaje prehram
bene proizvode. Podaci su podijeljeni u trinaest tablica: Customers, Empl0yees
Orders, Order Detaild, Products i tako dalje.
Svaka tablica u relacijskoj bazi podataka je organizirana u u redove, gdje svaki red
predstavlja jedan zapis (engl. record). Redovi su organizirani u stupce. Svi redovi u
tablici imaju istu strukturu stupaca. Na primjer, tablica Orders ima tri stupca: Orde-
rlD, CustomerlD, OrderDate.
Za bilo koju narudbu trebate znati ime kupca, adresu, ime osobe za kontakt itd
Mogli biste spremiti tu informaciju sa svakom narudbom, ali to bi bilo neuinkovito
Umjesto toga koristite drugu tablicu koja se zove Customers i u kojoj svaki red pred-
stavlja jednog kupca. U tablici Customers postoji stupac CustomerlD. Svaki kupac ima
jedinstveni identifikator i to polje je oznaeno kao primarni klju (engl. primary key)
za tu tablicu. Primarni klju je stupac ili kombinacija vie stupaca koji jednoznano
identificiraju zapis u tablici.
Tablica Orders koristi CustomerlD kao vanjski klju. Vanjski klju (engl. foreign key)
je stupac (ili kombinacija vie stupaca) koji je primarni klju za neku drugu tablicu.
Tablica Orders koristi CustomerlD (primarni klju za tablicu Customers) da odredi
koji kupac je napravio narudbu. Da biste odredili adresu za narudbu, moete kori-
stiti CustomerlD klju da biste potraili zapis kupca u tablici Customers.
Ovakva upotreba vanjskih kljueva je posebno korisna prilikom prikazivanja veza tipa
jedan prema vie" ili vie prema jednom" izmeu tablica. Odvajanjem informacija
u tablice koje su povezane vanjskim kljuevima, izbjegavate ponavljanje informacija
u zapisima. Jedan kupac, na primjer, moe imati vie narudbi, ali je neuinkovito
338 | Programiranje C#
|: navljati informacije o kupcu (ime, telefonski broj, dozvoljeni limit i tako dalje) u
?sva.ik,;i zapis naru
rud
dbe. Pro ces uklan jan jaja suv
uvin
inih
ih informacija iz zapisa i njihovo
preba- civanje u zasebnu tablicu se zove normalizacija.
Normalizacija
Normalizacija ne sam o da omoguava uinkovitije koritenje baze podataka, ve i sma-
njuje vjerojatnost gubitka. Ako bi zadrali ime kupca u tablici Customers i u tablici
, Orders, onda bi postojao rizik da se promjena u jednoj od tablica odrazi i na drugu
tablicu- Zato, ako biste promijenili adresu kupca u tablici Customers, ta promjena se
ne bi vidjela u svakom redu tablice Orders (i dosta truda bi bilo potrebno da osigurate
da se promjene vide). Dranjem CustomerlD identifikatora u tablici Orders, moete
slobodno mijenjati adresu u tablici Customers i promjena e se automatski odraziti
j na svaku narudbu.
Ba kao to programeri u C # jeziku ele da prevoditelj primjeti pogreke prilikom
prevoenja, a ne prilikom izvoenja, tako i programeri baza podataka ele da im baza
podataka pomogne da izbjegnu mogunost gubitka podataka. Prevoditelj pomae da
se izbjegnu pogreke u C# jeziku nametanjem pravila jezika (na primjer, ne moete
koristiti varijablu koju niste definirali). SQL Server i druge moderne relacijske baze
podataka izbjegavaju pogreke nametanjem ogranienja koja moete sami definirati.
Na primjer, baza podataka Customers oznaava CustomerlD kao primarni klju. To
I stvara ogranienje primarnog kljua u bazi podataka koje osigurava da je svaki Custo-
merlD jedinstven. Ako u bazu podataka dodate kupca Liberty Associates, lnc. iji
identifikator CustomerlD ima vrijednost LIBE i onda pokuate dodati kupca Liberty
Mutual Funds sa vrijednosti LIBE identifikatora CustomerlD, onda bi baza podataka
odbacila taj drugi zapis zbog ogranienja primarnog kljua.
SQL
Najpopularniji jezik za izradu upita i rad s bazama podataka je SQL. SQL je dekla-
rativni jezik, za razliku od proceduralnih jezika, i moe proi neko vrijeme dok se
naviknete raditi sa deklarativnim jezikom kad ste se ve navikli na proceduralne jezike
kao sto je C# .
f
M Poglavlje 14: Pristup podacima kroz AD0.NET | 339
SQL je baziran na upitima. Upit (engl. query ) je deklaracija koja vraa skup zapisa i
baze podataka.
Na primjer, moete poeljeti da vidite sve zapise iz tablice Customers u kojima je
adresa kupca u Londonu. Da biste to napravili, napiite:
Select CustomerID, CompanyName from Customers where city = 'London'
Ovaj upit trai od baze podataka da uzme OrderID identifikator i ime proizvoda iz
tablica kojih se to tie. Prvo treba pogledati u tablicu Order Details (koju smo skra-
eno nazvali od), zatim to povezati s tablicom Orders za svaki zapis u kojem je OrderID
u tablici Order Details jednak kao OrderID u tablici Orders.
Kad poveete te tablice, moete rei ili Uzmi svaki zapis koji postoji u bilo kojoj od
tih tablica" (ovo se zove vanjski spoj (engl. outer join)) ili kako sam napravio u ovom
sluaju, Uzmi samo one zapise koji postoje u obje tablice" (ovo se zove unutarnji spoj
(engl. inner join)). To jest, unutarnji spoj odreuje da se uzmu samo zapisi u tablici
Orders koji odgovaraju zapisima u tablici Order Details po polju OrderID (on o.Orde-
rid-od.Orderid).
r<,
^ SQL spojevi su standardno postavljeni da budu unutarnji spojevi.
340 I Programiranje C#
SQL deklaracija pita bazu podataka da napravi unutarnji spoj sa tablicom Orders i
pritom uzme svaki, red u kojem je ProductID u tablici Products jednak kao ProductID
u tablici Order Details.
Zatim napravite unutarnji spoj sa kupcima za one redove gdje je CustomerlD jednak u
tablicama Orders i Customers.
fja kraju, napravite ogranienje tako da se kao rezultat uzmu samo oni redovi u kojima
je CompanyName ona tvrtka koju traite, a datumi su u estom mjesecu.
Ova kolekcija ogranienja pronalaze samo tri odgovarajua zapisa:
OrderID ProductName
Ovaj izlaz pokazuje d aje bila samo jedna narudba (10248) u kojoj je kupac imao tra-
eni identifikator i u kojoj je datum bio esti mjesec 1996. Ta narudba je proizvela
tri zapisa u tablici Order Details i koristei identifikatore proizvoda u ova tri zapisa,
dobivate ime proizvoda iz tablice Products.
Moete koristiti SQL ne samo za pretraivanje i uzimanje podataka, ve i za stvara-
nje, auriranje i brisanje tablica i openito upravljanje i rad sa sadrajem i strukturom
baze podataka.
Za puno objanjenje SQL jezika i kako ga to bolje iskoristiti, preporuam vam knjigu Tran-
sactSQL Programming (u izdanju 0 Reilly Media). Ako koristite SQL bazu podataka, a da
to nije SQL Server, onda bi bilo dobro da prouite SQL Pocket Guide (takoer u izdanju
0 Reilly Media) jer svaki dobavlja moe koristiti malo drugaiji SQL dijalekt".
DataRelation objekti
Osim kolekcije Tables, DataSet ima i Relations svojstvo koje vraa DataRelationCollei
tion kolekciju koja se sastoji od DataRelation objekata. Svaki DataRelation objekt p re d
stavlja vezu izmeu dvije tablice kroz DataColumn objekte. Na primjer, u Northwindbal|l
podataka tablica Customers je u vezi sa tablicom Orders preko stupca CustomerID.
Priroda ove veze je od jednog prema vie, ili od roditelja prema potomku. Za bilo koj||
narudbu, bit e samo jedan kupac, dok bilo koji kupac moe biti zastupljen u vill
narudbi.
Redovi
Kolekcija Rows vraa skup redova za tablicu. Koristite ovu kolekciju da ispitate rezuk'Jl
tate upita u bazi podataka, prolazei kroz redove da bi ispitali svaki zapis. Programerif"
koji su koristili ADO su esto zbunjeni time to nema objekta RecordSet sa njegovirti1^
moveNext i movePrevious naredbama. Kod ADO.NET-a, ne prolazite kroz DataSet, ve'
umjesto toga pristupite tablici koju trebate i onda moete proi kroz kolekciju Rows,
obino sa foreach petljom. Vidjet ete to u prvom primjeru u ovom poglavlju.
Adapter podataka
DataSet je apstrakcija relacijske baze podataka. A DO.N ET koristi DataAdapter kao
most izmeu DataSet objekta i izvora podataka, a to je baza podataka. DataAdapter
prua Fill() metodu za uzimanje podataka iz baze i punjenje DataSeta.
DataAdapter objekt
Umjesto da vee DataSet objekt preblizu arhitekturi baze podataka, ADO.NET koristi
DataAdapter objekt da posreduje izmeu DataSet objekta i baze podataka. Time se
DataSet objekt odvaja od baze podataka i omoguava da jedan DataSet predstavlja
vie izvora podataka.
342 | Programiranje C#
fnativa stvaranju DataSet (i DataAdapter) objekta je da napravite DataReader. Data-
fgr prua spojeni pristup kolekciji tablica samo za prosljeivanje i samo za itanje
ljenjem ili S Q L deklaracije ili pohranjene procedure. DataReader objekti su jed -
i n i objekti idealni za ispunjavanje kontrola podacima i zatim prekidanje veze s
dinskom bazom podataka.
.,ko nemate instaliran SQL Server, odaberite Quickstart Tutorials u Microsoft .NET
ramework SDK skupini programa (nakon to instalirate Visual Studio ili .NET Frame-
work SDK). Pojavljuje se Web stranica koja nudi opciju da instalirate Microsoft SQL
jerver Desktop Engine (MSDE). Nakon to instalirate MSDE, podesite QuickStart
irutorials (to e napraviti Northwind pokusnu bazu podataka). Da biste koristili ovu
bazu podataka, trebate sljedei niz znakova za spajanje:
"server=(local)\\NetSDK; Trusted_Connection=yes; database=northwind"
Kad imate DataAdapter spremni ste napraviti DataSet i napuniti ga s podacima koje ete
uzeti s pomou SQL iskaza za odabir:
DataSet DataSet = new DataSet();
DataAdapter.Fill(DataSet,"Customers");
To je to. Sad imate DataSet i moete postavljati upite i raditi s podacima. DataSet ima
kolekciju tablica, a vas zanima samo prva jer ste uzeli samo jednu tablicu:
DataTable dataTable = DataSet.Tables[o];
using System;
using System.Collections.Ceneric;
using System.ComponentModel;
using System.Data;
using System.ata.SqlClient;
using System.rawing;
using System.Windows.Forms;
#endregion
namespace WorkingWithADONET
{
partial class ADONetFormi : Form
{
public ADONetForml()
{
InitializeComponent();
344 | Programiranje C#
((primjer 14-1. Rad sa ADO.NET-om (nastavak)
// Uzima jednu tablicu iz DataSet
DataTable dataTable = DataSet.Tables[0 ];
lbCustomers.Items.Add(
dataRow["CompanyName"] +
(" + dataRow["ContactName"l + ")" )
}
| Sa samo nekoliko redova koda izvukli ste skup podataka iz baze i prikazal, te podatke
| upadajucem popisu, kao to je prikazano na slici 14-1.
AlfredsFuttakiste(Mana Andere) A
Ana TfujilloEmparedadosyhelados (Ana TiujillN
Anlonio Moreno Taquen'a (AnlonioMoreno)
Aroundthe Hom (Ihomas Haidy) "
Baglunds snabbkop (ChdstinaBaglund)
BlauerSee Detkatessen(Hama Moos)
Blondesdds!pereelfils(FrederiqueOteaiK)
BoMo Comidaspreparadas (MartinSommet)
Bon app'(Laurence LebJian)
Bottom-DollarMaikets (Szabelh Lincoin)
B'sBeverages (MelonaAshvrorth)
CactusComidasparalevaz(PatricioSimpson)
Cenirocomeraal Modezuma (FrandscoChanc
Chop-sueyChinese(Yang Wang)
Comereio Minero(PednoAfonso)_____ jjg|
Ovaj upit se spaja s Northvvind bazom podataka na C: disku (tona putanja kod vas
moe biti drugaija).
Z atim promijenite DataAdapter objekt iz SqlDataAdapter u OLEDBDataAdapter:
Ol e D b D ataAdapter Da ta A dapter =
new Ol e D b D ataAdap ter (command Stri ng , co nnectio n String) ;
Ovaj projektni predloak se nastavlja dalje kroz dva upravljana izvora podataka. Za
svaki objekt ije ime klase poinje sa ,,Sql postoji odgovarajua klasa koja poinje sa
,,01eDb. Primjer 14-2 prikazuje kompletnu OLE DB inaicu primjera 14-1.
using System;
346 I Programiranje C#
Primjer 14-2. Koritenje ADO
Managed Providera (nastavak)
using System.Collections.Ceneric;
using System.ComponentModel;
using System.Data;
using System.Data.01eDb;
using System.Drawing;
\using System.Windows.Forms;
tfendregion
: namespace Us ingADOManagedProvider
J
partial class ADONetFormi : Form
: {
public ADONetForml()
InitializeComponent();
" Povezivanje s Northwind bazom podataka
string connectionString
"provider=icrosoft.JET.OLE8.4.o-
+ "data source = c: Wnwind.mdb'1,
lbCustomers.Items.Add(
dataRow["CompanyName"] +
j ( + dataRow["ContactName"] + ")" );
}
}
z u
ovom sluaju je identian onom iz
prethodnog primjera (slika 14-2).
Lets you dioosethedatabase objerts you are Interested In and creates a DataSetin the
current project as a result
S l i k a 1 4 - 3 . a r o b n j a k D a t a S o u r c e C o n f ig u r a t io n
OLE DB. Managed Provider je univerzalni}! nego SQL Managed Provider i moe se
koristiti za spajanje na SQL Server kao i na bilo koji OLE DB objekt. Kako je SQL
Server Provider optimiziran za SQ L Server, uinkovitije je koristiti izvor po ata
koji je specifian za SQL Server prilikom rada s SQL Serverom. S vremenom, vect broj
specijaliziranih upravljanih izvora podataka e biti dostupan.
348 | Programiranje C#
|d $ kontrolama za podatke
. d isprobajmo drugaiji pristup koji je vie deklarativan. Napravite novi Windows
ijrms Solution (nazovite ga DeclarativeDataDisplay). Poveajte obrazac i promi-
|f)ite mu *me u iDeclarativeDB.es i dodajte naslov Declarative Data Base. Povucite
ata&ridVievv na obrazac.
'a(j je na svom mjestu, pojavit e se izbornik Action. Pritisnite padajui popis da iza-
%rete izvor podataka. Pritisnite Add Project Data Source kako biste pokrenuli arob-
njaka Data Source Configuration. Pritisnite Next da odaberete tip podataka, kao to
prikazano na slici 14-3.
(Odaberite Database i pritisnite Next. To vas vodi do arobnjaka Data Source Configu-
.ation gdje moete odabrati New Connection (slika 14-4).
Choose from the Hst of data connections currently in Server Explorer or add a new
connection if the one youwant is not listed.
jV jj I New Connection..
Connection Detafc
Provider:
. Connection string:
<Badc
UC
J S lik a 1 4 - 4 . O d a b i r v e z e
S p e c i f y t h e f o l o w i i g t o c o n n e c t t o S Q L S e r v e r d a t a :l
. S e tec t o r e n ter a serv er n am e:
)&ACH ,Y ,:J j R e fres h |
e n t e r r f c r m a t to n t o lo g o n t o t h e se r v e r :
0 O s e W h d o w s N T Integrztgd Securltf
U s e a s o e c iflc u s e r ID a n d p a s s w o rd :
.
U se r ID : l
Psiswofd: ( * ............................................................... i
0 S a v e m y p a ss w c rd
S e i e c t o r e n t e r a d a ta b a s e n a ft e ;
| N crlh v v in d __ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
0 A t t a c h a d a t a b a s e f il e a s a f il e n a m e :
L _ " " ~ ~
0 Yes.savetheconnectionas;
)NorthwindConnedion
0 Includesensilivedata(e.g.passvvoid)inconnectionstring.
Bit e prikazan sadraj objekta DataSet koji ste odabrali. U ovom sluaju, proirite,
tablice i proirite tablicu Customers. Odaberite sve stupce osim stupca Region (da b ij
pokazali da upit ne mora vratiti sve stupce) i pritisnite Finish.
350 | Programiranje C#
ja b e rite jeziak za mreu podataka i zatim Edit Columns. Uredite zaglavlja stupaca
^smislen tekst, kao sto je prikazano na slici 14-7.
B o r td c c A m P ra p e rttes
listi s
; > f t e 3d c n l y F ls e
, 'j V i s b f e T ru e
k .W ld ih 100
-C .
t jA u lo S ltt O lt e r ia N one
,; ^ C o n ( e x t M e n u S t d p in o n e j
C o m p sn v N am e
v iR e s e ta tte T ru e
- 'S o r t M o d e Automate
. T o o r n p T e r t
.;D a t a P r f ip e r ty N a i T e C o n ip a n y N sr n e
rtiTag
OtSPlf 1 %
H e s tfs r T e jr t ' ; x C o tn p a n y N a m e
B M lsr
C o tm iT y p e O d f 3G i ( d v t 0w T e x l 8o x C o i n
H ead erT C T t
C o fc n r iH a a c te tT e r t.
^ogledajte podruje ispod mree podataka i vidjet ete tri objekta: northwindDataSet
f stomerDataConvertor i customersTableAdapter kao to je prikazano na slici 14-9.
r;t!!^ScMiooE*plffSJOM
SVVmT
njdaUGridAe! Srjten.WWow/*os.M*&t
Svaki od njih predstavlja objekt ija svojstva moete podesiti tako to ete ga pritisnuti;1;
i podesiti svojstva u prozoru Properties.
352 | Programiranje C#
ovomsluaju runo podeavate nizove znakova za povezivanje i odabir i onda stva-
^teSqlDataMaptei iDataSet da uzmete podatke. Zatim povezete DataSource svojstvo
ataCr.idView sa Default pogledom tablice Customers koju ste uzeli.
%bodno moete postaviti svojstvo od DataGridView programski ili deklarativno te
'-oete mijeati i usporeivati pristupe. Ali oito, Microsoft je obavio veliki posao
iko bi vam omoguio povlaenje i isputanje kontrola za veze s bazama podataka na
jbrazac radi jednostavnijeg meudjelovanja s ADO.NET-om.
;ko zadrite ovu vezu moi ete ju ponovno upotrijebiti (kao to ete vidjeti u sljede-
Bm primjeru) ili koristiti njezinu podrku za transakcije.
K a d ste to napravili, spremni ste d a popunite DataCridView (primjetite da sam ovaj put
koristio standardno ime za DataCrid):
dataGridl.DataSource=
myDataSet.Tablesf"Customers].DefaultView;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Windows.Forms;
#endregion
namespace CustomizedDataSet
{
partial class CustomizedDataSet : Form
{
private System.Data.SqlClient.SqlConnection myConnection;
private System.Data.DataSet myDataSet;
private System.Data.SqlClient.SqlCommand myCommand;
private System.Data.SqlClient.SqlDataAdapter DataAdapter;
public CustomizedDataSet()
{
InitializeComponent();
string connectionString = "server=localhost;" +
"Trusted_Connection=yes; database=northwind";
myConnection = new
System.Data.SqlClient.SqlConnection( connectionString );
myConnection.Open ();
354 | Programiranje C#
p rim jer 1 4 -3 . P r i l a g o a v a n j e D a t a S e t o b j e k t a ( n a s t a v a k )
I I Prikazuje ga u mrei
dataGridViewl.DataSource =
myDataSet.Tables["Customers"].DefaultView;
}
}
}
356
I.N ET Web usluge se proiruju na koncept distribuirane obrade zbog izrade kompo-
Inenti ije metode mogu biti pozvane preko Interneta koritenjem standardnih proto-
ikola. Te komponente mogu biti napisane u bilo kojem .NET jeziku i komuniciraju
Iskoritenjem otvorenih protokola koji ne ovise o platformi. Na primjer, burzin poslu-
|itelj moe pruiti Web uslugu koja uzima simbol dionice sa pominog prikaza kao
jf parametar i vraa cijenu. Aplikacija moe kombinirati tu uslugu s nekom drugom uslu-
|gom druge tvrtke koja takoer uzima simbol dionice, ali vraa podatke o kompaniji.
^Projektant aplikacije se moe usredotoiti na stvaranje novih vrijednosti s pomou
ovih usluga, umjesto kopiranja iste usluge za svoju aplikciju.
|Ovo poglavlje opisuje programiranje Web Forms obrazaca i Web usluga koritenjem
Ijezika C# .
I
^Razumijevanje Web Forms obrazaca
ASP.NET 2 .0 Web Forms obrasci su nasljednici jako uspjenih ASP.
0%
d N ET 1.x obrazaca, koji su naslijedili ASP stranice. Cilj ASP.NET 2.0
____I obrazaca je smanjivanje koliine koda za 70% u odnosu na ASP 1.x.
To znai da je Web programiranje sve vie deklarativno, a ne program-
sko. To jest, vi deklarirate kontrole na obrascu radije nego da piete (i
ponovno piete) kod.
jPVeb Forms obrasci implementiraju programski model u kojem se Web stranice dina-
Bmiki stvaraju na Web posluitelju za dostavu pregledniku preko Interneta. Sa Web
lpForms obrascima stvarate ASPX stranicu s manje-vie statikim sadrajem koji se
pastoji od H TM L-a i Web kontrola i piete C# kod kako biste dodali dodatni dina-
^(niki'Sadraj. C # kod se izvodi na posluitelju, a proizvedeni podaci se spajaju s
deklariranim objektima na stranici kako bi bila napravljena HTML stranica koja se
||alje natrag pregledniku.
Postoje tri kritine toke iz prethodnog odlomka kojih se treba primiti i koje treba
ijttiati na umu kroz cijelo ovo poglavlje:
||; Web stranice mogu imati i HTML i Web kontrole (to je opisano kasnije u ovom
poglavlju).
| i Sva obrada se obavlja na posluitelju (moete imati obradu na strani klijenta kori-
tenjem skriptnib jezika, ali to nije dio ASP.NET-a).
|| Web usluge mogu, naravno, biti napisane na bilo kojem jeziku i na bilo kojoj platformi. Bit Web usluga je
||?da su neovisne o platformi. Za potrebe ove knjige fokusirat emo se na stvaranje i koritenje Web usluga
|g.spomou .NET-a.
358 | Programiranje C#
Uobiajeno je da ASP.NET metode za obradu dogaaja vraaju void i uzimaju dva
parametra. Prvi param etar predstavlja objekt koji izaziva dogaaj. Drugi param etar,
argument dogaaja, sadri informaciju specifinu za dogaaj, ako postoji. Za veinu
dogaaja, argum ent dogaaja je tipa EventArgs, koji ne izlae ni jedno svojstvo. Za
neke kontrole, argum ent dogaaja moe biti tipa izvedenog iz EventArgs koji moe
izloiti svojstva specifina za taj tip dogaaja.
Stanje
Stanje (engl. State) Web aplikacije je trenutna vrijednost svih kontrola i varijabli za tre-
nutnog korisnika u trenutnoj sesiji. Bitno svojstvo Weba je da je to okoli koji nema
stanja. To znai da se prilikom svakog slanja posluitelju stanje prije slanja gubi, osim
ako projektant ne uloi velike napore da sauva znanje o toj sesiji. ASP.NET prua
podrku za odravanje stanja korisnikove sesije.
Kad god je stranica poslana posluitelju on je ponovno napravi od poetka prije nego
to ju vrati pregledniku. ASP.NET osigurava mehanizam koji automatski odrava sta-
nje posluiteljskih kontrola (ViewState) neovisno o HTTP sesiji. Prema tome, ako
ponudite popis a korisnik odabere neke njegove opcije, taj odabir se uva nakon to je
stranica poslana na posluitelj i zatim ponovno vraa klijentu.
Uitavanje
Ako se pojavi potreba, poziva se CreateChildControlsf) metoda da napravi i inici-
jalizira posluiteljske kontrole u kontrolnom stablu. Stanje se ponovno postavlja
i kontrole obrasca sadre podatke s klijentove strane. Moete modificirati fazu
uitavanja obradom dogaaja Load sa OnLoadf) metodom.
Slanje promjena
Ako se dogodi promjena stanja izmeu trenutnog stanja i prethodnog stanja, doga-
aji promjene se izazivaju preko RaisePostDataChangedEventf).
Obrada povratnih dogaaja
Dogaaj na klijentskoj strani koji je prouzroio slanje podataka se obrauje.
360 | Programiranje C#
Stanje prije generiranja
Ovo vam je zadnja ansa da koritenjem OnPreRender() metode promijenite
izlaz prije vraanja podataka klijentu.
Snimanje stanja
Na poetku ivotnog ciklusa sauvano stanje je u.tano iz skrivene varijable
Sad je pohranjeno natrag u skrivenu varijablu i ostaje kao objekt niza koji
ce zavriti povratni put do klijenta. To moete zaobii koritenjem SaveView-
S tate () metode.
Generiranje
U ovoj fazi se stvara izlaz koji se vraa natrag pregledniku. To moete premo-
stiti koritenjem Render metode. Ako je potrebno, poziva se CreateChildCon-
tro ls O za izradu i imcijaliziranje posluiteljskih kontrola u stablu kontrola.
Odlaganje
Ovo je zadnja faza ivotnog ciklusa. Tada vam se prua prilika da napravite
zavrno ciscenje , oslobaanje referenci dragocjenih resursa, kao to su veze
prema baz, podataka. Moete ju modificirati koritenjem isposef) metode.
Visual Studio stvara mapu ProgrammingCSharPWeb u mapi koju ste naznaili i unutar
te mape stvara Default.aspx stranicu (za korisniko suelje), Default.aspx.cs (za kod)
General
A d d -in/M ac ros S ecurity
A u to R e co ve r
D ocum ents [ c : \D o c u m e n t s a n d S e ttin g s \3 e s s e \M y Docum ents\V isual ShK | j B row s e... |
F o nts and Colors
St) Help Lo c atio n o f Visual Studio ite m tem p la tes :-------------------------------------- (------------------------
lm p o r l:/ x p o r t S ettings [ c :\D o c u m e n t s a n d S e t t in g s \ _ J ^ s s ^ y _ p o c u ^ n ^ s u o l 5 t u ( j | B row s e... j
In te rn a tio n a l S ettings
0 S h o w O u tp u t w in dow w hen build s ta r ts
K ey b oa rd
0 Alw ays s h o w E rror L is t if buifd fln is hes w ith e rro rs
T ask List
0 T rac k Ac ttv e Ite m ln S olution Ex ptorer
W e b 0 row s er
0 Show a d v anc ed bulkJ confkgurations
(50 P erform an ce
0 A l w a y s s how s olution
0 S ave ne w p ro je c ts w hen c re a ted
0 W a rn us er vvhen th e p ro je c t lo c a tio n is n o t tru s te d
VB D e fa u lts
V C + + Directories
V C + + P ro je c t S ettings
[ OK j[ Cancel }
Datoteke s kodom
& ----- Napomena za ASP.NET 1.1 programere: model razdvajanja koda za
<T ASP.NET je promijenjen. U inaicama 1.x, datoteka s kodom je detim-
f rala klasu koja je izvodila iz Page. Ona je sadravala varijable instanci
za sve kontrole na stranici, sa eksplicitnim povezivanjem dogaaja uz
upotrebu delegata i .aspx stranice dobivene od klase.
U inaici 2 .0 , ASP.NET stvara samo jednu klasu od ,aspx stranice i
definicija parcijalne klase iz datoteke s kodom.
A SP N ET moe zakljuivati instance kontrole i izvoditi povezivanja
dogaaja iz koda prilikom prevoenja. Prema tome, nova datoteka s
kodom sadri samo kod koji trebate, kao to su metode za obradu doga-
aja, ali ne i varijable instanci ili eksplicitne veze izmeu dogaaja^
Nove datoteke s kodom su jednostavnije, lake ih je odravati i uvijek
su usklaene sa ,aspx stranicama.
Pogledajmo malo podrobnije .aspx datoteke i datoteke s kodom koje generira Vis .
Studio. Ponite tako to ete preimenovati Default.aspx u HelloWeb.aspx. Da ist e
362 | Programiranje C#
. .jir.ili. zatvorite datoteku Deault.aspx i zatim pritisnite desnom tipkom mia njeno
. jrjjc u prozoru Solution Explorer. Odaberite Rename i upiite ime HelloWeb.aspx.
Tako ete promijeniti ime datoteke, ali ne i klase. Da biste promijenili ime klase priti-
snite desnom tipkom mia ,aspx stranicu, odaberite View Code i zatim preimenujte
5'ldasu HelloWeb_aspx. Vidjet ete malu liniju pokraj imena. Pritisnite ju i otvorit ete
pametnu oznaku koja omoguava promjenu imena klase. Pritisnite Rename Defa-
;ult_aspx u HelloWeb_aspx i Visual Studio e se pobrinuti da se svaka pojava Defa-
j ult_aspx zamijeni s pravim imenom, kao to je prikazano na slici 15-3.
iS lika 1 5 -3 . M ije n ja n je i m e n a k l a s e
|||(Na nesreu, (barem u beta inaici) ime klase nije promijenjeno u HelloWeb.aspx pa se
^1: vratite u HelloWeb.aspx datoteku i promijenite ClassName atribut direktive stranice u
!|| HeltoWeb_aspx:
i|fL. <%@ Page Language="C#" CompileWith="HelloWeb.aspx.es"
m
Sag; ClassName=HelloWeb_aspx" %>
|:W eb Forms pretpostavlja da trebate barem jedan obrazac da biste upravljali korisni-
kim djelovanjem i stvara jedan kad otvarate projekt. Atribut runat="server" je klju
itave magije posluiteljske obrade. Bilo koja oznaka s ovim atributom se uzima kao
(posluiteljska kontrola koju izvodi ASP.NET kostur na posluitelju. Unutar obrasca
Visual Studio je postavio div oznake kako bi omoguio umetanje kontrola i teksta.
Kad ste napravili prazan Web Forms obrazac prva stvar koju biste mogli poeljeti ui-
niti je dodati tekst na stranicu. Prebacivanjem u HTML pogled moete dodati skriptu
i HTML kod direktno u datoteku ba kao to to moete kod klasinog ASP-a. Doda-
vanje sljedeeg reda koda u tijelo HTML stranice e prikazati pozdravnu poruku i
trenutno lokalno vrijeme na stranici:
: Hello World! It is now <% = DateTime.Now.ToString() %>
Oznake <% i %> funkcioniraju jednako kao i u klasinom ASP-u, pokazujui da kod
dolazi izmeu njih (u ovom sluaju C# ). Znak =odmah na poetku oznake izaziva da
ASP.NET prikae vrijednost, jednako kao poziv metode Response.Write(). Jednako
tako biste mogli napisati red koda:
Hello World! It is now
<% Response.Write(DateTime.Now.ToString()); %>
) Pac>. - 0 @ [1 ^ P 5 rc h ^ F a v crto # j
Address l^rhttp:;/localho5t:27396/Programmin9CSharpWeb/HelloWeb.aspx v j 0 Go
locai intranet
^]Done
S l i k a 1 5 - 4 . H e l lo W o r l d u A S P . N E T 2 . 0
slici 15-5.
U ovom dijalokom okviru je podrazum ijevano - ^ c i j ^ p u n i t e (iako
je p o t r e f i o , da dvorite) datoteku. P ritisnite O K da biste om ogu ili otkri-
vanje pogreaka za aplikaciju.
| OK |[ Cancel Help
364 1 Programiranje C#
odavanje kontrola
psluiteljske kontrole moete dodati na Web Forms obrazac na tri naina: upisi-
vanjem HTML koda u HTM L stranicu, povlaenjem kontrola s palete s alatima na
|jesign stranicu ili programski, dodavajui ih prilikom izvoenja. Na primjer, pretpo-
stavimo da elite koristiti gumbe kako biste korisniku omoguili da odabere jednog
fjd tri isporuitelja iz Northwind baze podataka. Moete napisati sljedei HTML kod
'.'unutar <form> elementa u HTML prozoru:
<asp:RadioButton GroupName="Shipper" id="Speedy"
text = "Speedy Express" Checked="True" runat="server">
</asp:RadioButton>
<asp:RadioButton GroupName="Shipper" id="United"
text = "United Package runat="server">
</asp:RadioButton>
<asp:RadioButton GroupName="Shipper" id="Federal"
text = "Federal Shipping" runat="server">
</asp:RadioButton>
\ biste preli iz jednog u drugi nain rada, promijenite pageLayout svojstvo doku-
menta u Visual Studio .NET-u.
IMoete popraviti izgled radio-gumba mijenjanjem svojstava u prozoru Properties,
Ukljuujui pismo, boju, broj stupaca, smjer ponavljanja (okomito je podrazumije-
vano) i tako dalje.
S l i k a 15-6. U r e iv a n j e k o l e k c i j e L i s t l t e m s
V -----
SciobonEspibrer-SoMion'Proofanifrt... ? X
itionProgremminpCSharpVVab(2) (l profeti)
jC:\
jC:\Doc
Documefits and 5et
5ettm<js\
tm<js\Jese
Jese\
se\My Oocu
Oocun
B
Oata
HelaWeb.
eb.aspx
i, Vfeb.Canfig
f^'oWtonExpiorerj^ttW5Yiew
Propertles w ? x
R adloB
loB utt
uttonU
onUstl Sys
System.Web.
eb.UI.WebCo
bCortn
S l i k a 15-7. P r e b a c i v a n j e i z m e u D e sig n i S o u r c e p r o z o r a n a k o n d o d a v a n j a g r u p e r a d io - g u m b a
366 i Programiranje C#
posluiteljske kontrole
Web Forms obrasci nude dva tipa posluiteljskih kontrola. Prve su posluiteljske HTML
kontrole. To su HTML kontrole koje oznaavate s pomou atributa runat=Server.
; alternativa oznaavanju HTML kontrola kao posluiteljskih kontrola je koritenje ASP.
\;i;T posluiteljskih kontrola koje se jo nazivaju ASP kontrole ili Web kontrole. ASP
kontrole su razvijene da dopune i zamijene standardni skup HTML kontrola. ASP kon-
trole osiguravaju dosljedan objektni model i dosljednije nazive atributa. Na primjer, ako
koristite HTML kontrole postoji veliki broj naina da se obrade upisani podaci:
<input type="radio">
dnput type="checkbox">
<input type="button">
; <input type="text">
<textarea>
Svaki od njih se ponaa drugaije i uzima druge atribute. ASP kontrole pokuavaju
: normalizirati skup kontrola dosljednim koritenjem atributa unutar objektnog modela
ASP kontrola. ASP kontrole koje odgovaraju prethodnim HTML posluiteljskim kon-
trolama su:
<asp:RadioButton>
<asp:CheckBox>
<asp:Button>
<asp:TextBox rows="l">
<asp:TextBox rows="5">
Povezivanje podataka
Razne tehnologije su nudile programerima mogunost povezivanja kontrola s poda-
cima tako da, ako bi podaci bili promijenjeni, kontrole bi odmah reagirale na tu
ipromjenu. Ali, povezane kontrole bi imale ogranienu funkcionalnost i izgledale bi
Projektanti ASP.NET-a su naumili rijeiti ove probleme i pruiti niz robustnih kon-
trola povezanih s podacima, koje bi pojednostavnile prikaz i promjenu podataka bez
rtvovanja izvedbe i kontrole preko korisnikog suelja. U inaici 2 .0 proirili su listu
povezivih kontrola i pruili vie gotovih funkcionalnosti.
Uprethodnom dijelu ste fiksno podesili radio-gumbe na obrascu, jedan za svaki od tri
isporuitelja u Northvvind bazi podataka. To ne mora biti najbolji nain da se to uini.
;:Ako promijenite isporuitelje u bazi podataka, morate iznova povezati kontrole. Ovaj
Ldio opisuje kako moete dinamiki napraviti ove kontrole i povezati ih s podacima u
bazi podataka.
Pritisnite padajui izbornik Select a data source i odaberite <New Data Source>. Dalje tre-
bate odabrati izvor podataka iz tipova podataka u vaem raunalu. Odaberite Databasei
otvara se dijaloki okvir Configure Data Source, kao stoje prikazano na slici 15-9.
368 | Programiranje C#
daberite New da konfigurirate novi izvor podataka i otvorit e se dijaloki okvir
onnection Properties. Odaberite ime posluitelja, kako se elite spojiti na posluitelj
'Ime baze podataka. Obavezno pritisnite Test Connection da testirate vezu. Kad sve
%de radilo pritisnite OK (slika 15-10).
C o n n e c t io n P r o p e r t ie s
~c* i
Spedfy the fo lorttng to ccroect to SQL Server dota:
i . Sdect ot onter a server nama:
C ACK
2. Enter In/ormaSonTo log ort to the server!
~a . [ I
O U s e Wlndow$ NT Integrated Security
C*i TertCcnneriMjij'^
&lika 1 5 -1 0 . K o n f ig u r ir a n je s v o js t a v a v e z e
akon toga svojstva veze e biti upisana u dijaloki okvir Configure Data Source. Pre-
gledajte ih i ako su u redu pritisnite Next. Na sljedeoj stranici arobnjaka dajte ime
vezi (na primjer, NorthWindConnectionString) ako ju elite pohraniti u konfiguracijsku
|atoteku koju ete moi ponovno koristiti.
~ad pritisnete Next dobit ete priliku da odaberete stupce koje elite uzeti ili zadate
~QL deklaraciju ili pohranjenu proceduru za uzimanje podataka.
V'
Otvorite padajui popis Tables i odaberite tablicu isporuitelja. Odaberite polja Ship-
,erID i CompanyName kao to je prikazano na slici 15-11.
'Pritisnite Next i testirajte upit kako bi provjerili dobivate li natrag vrijednosti koje
(oekujete (slika 15-12).
[sHppers__
Colim s:
Katun or*yurtquerows
!|0S*hWwlO
si__ -
Phc*
TestQuerv
x e c u te th e s elec t s ta te m e n t to p re v ie w th e result.
SELECT Statement:
SELECT [ShfpperlD]. [Companyt4ame] FROM [Shtooefs]
S l i k a 1 5 - 1 2 . T e s t ir a n je u p it a
Sad je vrijeme da RadioButtonList poveete s izvorom podataka koji ste upravo napra-
vili RadioButtonList (poput veine popisa) pravi razliku izmeu vrijednosti koja ce
biti prikazana (na primjer, imena tvrtke za dostavu) i vrijednosti tog odabira (na p
mjer, identifikatora tvrtke za dostavu). Postavite ova polja u arobnjaku koristei paa
jui popis, kao to je prikazano na slici 15-13.
370 | Programiranje C#
Choose Data Source
Choose a data source fbr the RadioButtonltst Items and a data field to tand fbr either the tex t or value,
or both.
[ip ID ataSourcel v jj
[companyName .v~j
Refresh Schema
Ispitivanje koda
Prije nego krenemo dalje trebate obratiti panju na nekoliko stvari. Kad pritisnete F5
da pokrenete aplikaciju, ona se pojavljuje u pregledniku Weba i vide se radio-gumbi
prema oekivanjima. Odaberite View -* Source i vidje ete da je pregledniku poslan
obini H TML, kao to je prikazano na slici 15-14.
Primjetne da HTM L ne sadri RadioButtonList. Kod sadri tablicu sa elijama unutar
Ikojih su standardni HTM L ulazni objekti i natpisi. ASP.NET je preveo kontrole koje
je. dodao projektant u HTM L razumljiv bilo kojem pregledniku.
O Speed yEjT T s j
O United Packjge Pite t t Format vie
view_ Help _ .............. .. ..........................................
........ ...
... ...................... .. ............ .........
......... . ; '-
OFtdera) Shjppntg
<1DCCtiPEhtmlPueuc"-//V3C//0TDrmi. 1.1//en" "trti:p://rww.*<3.org/TR/xhtnilll/OTO/xhtni1ll.td~>
<
<hhtm ea1dxm t1 lns>'http://w*w.w3.org/l999/xhtm1" >
i Uhtrle
ettaUdl>
edPage
)/otd1yt<
lax/
>formmeihod'postactlorc'Dafau1t.aspx" 1dforml'>
<1nout typ9"'h1dderVnam
<d1v>
p-'~ vIEVTSTATE
I f t i i ufat lmuvalr>/;V
</d1v>
Q 3ehP bOCW
BTJH
aQ2
lU
wl-N
:G2
lCuy2M xiJD
OkAO
TPE2eftW
M 9A
e2gFI0
C0s2
PQAW2dAng
zI2
BRDkW cj85P r5g
aI
PC
l O1
r8
hSP
e.iivz
iv3
ivzFO
pY
gy
oj
ovd
gW5k
cbpZ
yr2
vQ
yrv alF
gQ
- M
O U3ei2W
/> K5ievaCH3lcjHOVrfSpdGVkIFBhY2Th75i
<div><table1d-"ftad1oBirttonLlsil'' border."0">
Por'ftad<ltorB >ucton<L cls
dxtl1_r0tp
ru>tspe1edd-y"RG
adx1poreBsust<to
/n
laLblesltxl_/0t"d>type-rad1onameftad^oBirtionL^stlvalufi-"!" /x1abe!
for"fiad10ButconLlstl_lSonltedPackage</n
< / t r> r ^ ^ id - ''R d '
* oB u tto laLblesltxl_/ltM
d>xype-"rad1o" na/ne-'-RadloBirttonUstl" valueO" /xlabol
. *t? 'fSg;] for"Rad<1A
oe'u
><
tt^
orn^i.d
1sJi<
l_lf2)_1JtFeude"rA
aladsihol6piprlxntg
o<
n/
(.!iastlbe_12x'/ttd
yp
>e-"radloname-'Rad1oBirtxont.1stl"value-"3" /xlabel
. . '* < A r>
' </4foU
</ ?>
rm
</
</b
hodyl>
tm >
372 | Programiranje C#
3 Choose Sh ipper
per - Micr
Microsoft In tern et Explore r
F lle E d it V le w F a vo rite s Tool H elp
-v
Welcome to NorthWind
Your i ---------------------------- i
name: *------------- -----------------
O Speedy Express
Shipper: OUnited P^ a g e
OFederal Shipping
| O rd e r | [ C a n c e l |
</tr>
<tr>
<td colspan=" 2 " x asp : Labe l id="lblMsg"
runat=serverx/asp: Labelx/td>
</tr>
</table>
</form>
</body>
</html>
Kad korisnik pritisne Order gumb provjerit ete je li korisnik unio svoje ime i pruiti
povratnu informaciju o odabranom isporuitelju. Zapamtite, prilikom projektiranja
ne moete znati ime isporuitelja (ono se uzima iz baze podataka) pa ete u padajuem
popisu morati provjeriti odabrano ime (i identifikator).
Da biste sve to postigli prebacite se u Design nain rada i dvaput pritisnite gumb
Order. Visual Studio e prikazati stranicu s kodom i generirati metodu za obradu
dogaaja za Click dogaaj gumba.
A^
^ I Da bismo pojednostavnili ovaj kod neemo provjeravati je li korisnik
<*, J upisao ime u polje za tekst. Za vie informacija o kontrolama za pro-
vjeru koje ovo olakavaju, pogledajte knjigu Programiranje ASP.NET.
Dodajte kod za obradu dogaaja i postavite natpis tako da preuzme tekst iz polja za
tekst te tekst i vrijednost iz RadioButtonList:
void btnOrder_CUck( object sendei, EventArgs e )
{
lblMsg.Text = "Thank you " + txtNaine.Text.Triin() + You chose " +
rblShippers.Selectedltem.Text.T o S t rin g O + " whose ID is " +
rblShippers.SelectedValue.ToStringO;
374 | Programiranje C#
p u b lic p a c c ia l c la s s Shipx> er__ asi> x
<
p ro te c te d o v e r r id e |
Onlnit (System.EventArgs e)
v o id b tn O rd e r_ C nload(5ystem.EvertArg5
f t ~jnloatfLGMplBtfc p>y5temtEventArgs e)
lb lM s g . T e x c = OnPrelnit (System.EventArgs e)
r b lS h ip p e r s )* * Or>PreLoad(Sys(:em.EverrtArgse)
r b lS h ip p e r s OnPreRender (System.EventArgs e)
f t OnPreRenderComplete (5ystem.EventArgs e)
f t OnSaveStateCompIete (System.EventArgs e)
f t OnUnload (5ystem.EventArgs e)
Ponite tipkati OnLoad i kad je istaknuto pritisnite Tab. Bit e napravljen kostur metode,
ali njegovo podrazumijevano tijelo izbacuje NotImplementedException iznimku.
(Obriite iznimku i zamijenite ju s kodom:
rblShippers.Selectedlndex = 0;
:To odabira prvi gumb iz RadioButtonList. Postoji problem s ovim rjeenjem. Ako
pokrenete aplikaciju vidjet ete da je odabran prvi gumb, ali ako odaberete drugi (ili
(trei) gumb i pritsnete OK, vidjet ete da je prvi gumb ponovno odabran. Izgleda da
nie izvede OnLoad dogaaj, a u toj metodi za obradu dogaaja ponovno postavljate
;jne i kad je vraena natrag pregledniku kao rezultat pritiska na gumb OK.
Da biste to rijeili odabiranje prvog radio-gumba smjestite u i f deklaraciju koja pro-
vjerava da lije stranica vraena:
protected override void OnLoad(EventArgs e)
{
if ( UsPostBack )
{
rblShippers.Selectedlndex = 0;
}
}
.t M r e s s ! .. u o -a cm te n la u S h io D e rs /S h ip p e r. a s p x
Address^htlpi//toca1htJgj J j j j ^MgYgJ j PP^j L_- ! Ec - - l - ^ , lasav e -Logatf ::i: ilinkS
U1 - .............. -
V le lc c ro e to N o r th V T m d ____________________
fo sn u m . ,?
S T y o u Jesse Liberty. Vou chose United Package whore .a
using System;
using System.Data;
using System.Configuiation;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.l)I;
using System.W e b .U I .WebControls;
using System.Web.UI.WebControls.WebParts,
usine System.Web.UI.HtmlControls,
^ i-f ( tIsPostBack )
{
376 | Programiranje C#
primjer 15-2. Kod obrasca za Shipper.aspx.cs (nastavak)
rblSbippers.SelectedIndex = 0;
)
}
void btnOrder_Click( object sender, EventArgs e )
{
lblMsg.Text = "Thank you '' + txtName.Text.Triin() + Vou chose
rblShippers.SelectedItem.Text.ToStrifig() + " whose IO is " +
rblShippers.SelectedValue.ToStringO;
}
Web usluge
Ifl'.N E T Web usluge pomau da napiete komponente ije metode mogu biti pozvane
preko Interneta koritenjem bilo kojeg .NET programskog jezika. Projektanti koji rade
$ E W eb usluge mogu stvarati jednu na temelju druge, koristei prednost povezanosti kao
f j kljunog svojstva Weba. Stvaranje nove vrijednosti uzima prednost nad ponovnim
i otkrivanjem ve poznatih stvari.
Popis Web usluga koje mogu biti korisne projektantima i krajnjim korisnicima se ini
|neogranien. Trgovina knjigama bi mogla pruati Web uslugu koja uzima ISBN i vraa
Scijenu i podatak o dostupnosti knjige. Web usluga hotela moe uzimati datum dolaska
(i odlaska i broj gostiju, a vraati rezervaciju. Neka druga Web usluga moe uzimati
^telefonski broj i vratiti ime i adresu. Takoer usluga moe pruati informacije o vre-
! menskim prilikama i lansiranjima svemirskih atlova.
; Jedna aplikacija moe povezati usluge stotina manjih Web usluga iz cijelog svijeta. To
|Webu daje novu dimenziju: ne samo da se dobijaju i razmjenjuju infromacije, ve se i
fpozivaju metode i izvode aplikacije.
I/ Ovaj pogled na SOAP je uvelike RPC-orijentiran zato to .NET rako ohrabruje projektante da koriste
SOAP. Zapravo, SOAP je razvijen da alje poruke, ali .NET arhitektura implementira slanje poruka za
pozivanje metoda i pristupanje svojstvima na udaljenom objektu.
378 | P ro g ra m ira n je C#
Temptetes:
$ ASP.NET W eb Site
II
ASP.NET W e b S v lc e
^ P e rs o n a l W eb Site S ta rte r Kit
^ ASP.NET C rystal Reports W eb Site
g TjA dd New Online T em plate...
.: r ok j Cancel I
Visual Studio .N ET stvara kostur Web usluge i prua primjer metode usluge koju
..moete zamijeniti vlastitim kodom, kao to je prikazano u primjeru 15-3
f g l Primjer 15-3. Kostur Web klase kojeg je generirao Visual Studio .NET
uski; System.Web;
:.using System.We b.Services;
' using System.Web.Services.Protocols;
[HebMethod]
public string HelloWorld() {
return "Hello World;
}
|] '
|Da biste od tog kostura dobili kalkulator, zamijenite HelloWorld metodu sa pet drugih
|metoda: Add(), Sub(), Mult(), Div() i Pow(). Svaka uzima dva parametra tipa double,
|izvodi traenu operaciju i vraa vrijednost istog tipa. Na primjer, evo koda za izrau-
navanje zadane potencije broja:
public double Pow(double x, double y)
{
double retVal = x;
for (int i = o;i < y-l;i++)
retVal *= x;
}
return retVal;
}
Ne trebate izloiti sve metode klase kao Web usluge. Moete odabrati metode dodava-
njem [WebMethod] atributa samo onim metodama koje elite izloiti.
Ne oekuje se da se na ovoj URL adresi nalazi dokument. URL adrese se koriste jer
su praktian izvor jedinstvenih imena.
[UebServiceBinding(ConformanceClaims=VteiClaims.BPlO,EmitConfoimanceaaims = true)]
public class Service : System.Web.Services.HebService {
[WebMethod]
public double Add( double x, double y )
{
return x + y;
}
[WebMethod]
public'double Sub( double x, double y )
{
return x - y;
}
[WebMethod]
public double Mult( double x, double y )
{
return x * y;
380 | Programiranje C#
s i [klebtfethod]
|; public double Div( double x, double y )
return x / y;
;bMethod]
jlic double Pow( double x, double
double retVal = x;
for ( int i = o; i < y - 1 ; 1++ )
{
retVal *= x;
I' )
return retVal;
;f:
g p k a 1 5 -1 9 . P r i k a z t e s t n e s t r a n i c e W eb u s lu g e
j
Odabir metode vas dovodi do stranice koja opisuje metodu i omoguava vam da ju
S e rv ic e
Clickhei-ofordcompletelistofoperations.
Pow
P a A jm e te r V alue
x: lEZ!
IC
jjn v o k e i
: lo c a l h lra n et
Ako upiete vrijednost tri u prvo polje, etiri u drugo polje i pritisnete Invoke, zatrait
ete od Web usluge da tri podigne na etvrtu potenciju. Rezultat je u XML stranici
koja opisuje izlaz, kao to je prikazano na slici 15-21.
-3 h ttp
ttp://l
//localhost: 1997 5 /C a lcul ator W S/Se
S/S e m ce .as.
F ite E d it V ie w F a v o rlte s T o o ts H e lp -
Address g ) http://localhost:19975/CalculatDrWSyService.asmxAow m^ B Go
3 RoboForm Passcsrds ** {EUIdtentittes ^ j|Q Safenotes -li Unks
JDone i j^ localintranet
382 | Programiranje C#
I . Sve Web usluge mogu bici opisane u WSDL datotekama. WSDL doku
. ^^^uuienc moete
: vidjeti dodavanjem nastavka ?WSDL URL adresi Web usluge:
http://localhost:l9975/CalculatorWS/Service.asmx?wsdl
a ht
htttp:/
p://lo
/local
calhos
host:19975/CalculatorWS/Service.asrox?wsdl
t:19975/CalculatorWS/Service.asrox?wsdl - Micro
crosoft Internet Explor
lorer
File Edlt View Favorltes Toob Help m
;#
@Back '
; Adress j
li) lsi ii ^Psearcb ^FavoriSM
http://localhost:19975/Calci.iiatDfWS^erf:e.asm>;?wsdl
0 - ^ ' J [*10 M I i %
gRobcform - @Passcards * jb] IdenOties - (gjsafenotes - [SjFlllForrrts * I*}Sav w0 . r.-iT (L^Hide ; trk* ^eioglheT"
10
<?xrr>l vefsion=" . " encoding=utf-8n ?>
- <wsdl:definitions tvriifas. tp://sdu!inrts.>iifilso^p.t3nj/ivsill/scKJ|i/-
:-!Tn)r>yAri,= h n i i : / / n i i c r o s a h . c o n > / i ' r s t n / n u n u / t a ; H r > U i t c l i i n q / '
.,Tnlns:?o'tpc-nc=''litt|)://S(:h(*nk)i.Kinloo|).Qrg/soop/fiii(:ortiiiq/"
v.m!ns:n.ime-="hU|)://schi?nuis.xinlsoap.org/vfsc1l/inirMO/" tn;="hllp://lempuri.org/"
xrnlri2: littp :// vfv<vj.vv3.f)rcj/20Ul/XMl.5}clierrwt" .imlns: ;iVrpi>;="liU|i://5Cl)eitifis.xnilsofip.tjry/vt
3r, 1 1
^rni['?;Mtp="ht jj://scluim><i;.Mf)ilsffcip,f>ry/vv.sc l/ h U p /' t,3<geWamesp3ce=ufittp://tempurl.orq/*
niliv>:'v;t.dl=*t\Up;//5><;Jt3q\os.xmlsnop.org/vfsd1/">
- <wsl;types>
- <s:schema e1errientFormDefai.i! Mquo1ified" f3rgetr'I.aine?pace=Hhttp://tempuri.org/*>
- <s:element n3me=Add">
- <s:complesType>
- <s-. sequoce>
<s:element minOccurs=l" maxOccurs="l" narne=x" tvpe='s:doubte" />
< s : e le r n e n t m m O c c a r s = l maxOcct/rse"l name=y type="s:double />
</s:sequence>
</s:comple:<Type>
</<..elsmem>
- <s:etement name=AddResponse">
- <s:comples.Type>
- <s:sequence>
<s:e!ement rninOccurs"l maxOccurs="lMnaine=*AddResuU ivpes^ double" />
</v.sequence>
</s:comple:<Type>
</'s:e1emenl>
- <s:element name=*Sub">
- <s:complexType>
- <s:sequence>
<s:element minOccurs="l maxOccur$=l" nameax" type= s:doub1e" />
<s:element nunOccurss l maxOccuis="l* name-y" lype="s:doub1e />
</s:sequence>
</s:compleKType>
</s:e1ement>
- <s: element name-"8ubResponse*>
- <s:complexType>
. - <s:sequence>
<s:element minOccurs= lmaxOccurs=*l" names*8ubResuK type=*s:double* />
<r/s:sequence>
</s:compleKType>
</s:element>
Spone I, _.:<Q Local miranet
Detalji WSDL dokumenata su izvan dometa ove knjige, ali moete vidjeti d aje svaka
metoda potpuno opisana u strukturnom XML formatu. To je informacija koju SOAP
j. koristi kako bi omoguio klijentskom pregledniku da pozove metode Web usluge na
posluitelju.
, Stvaranje posrednika
a
& Prije nego napravite klijentsku aplikaciju za meudjelovanje sa Web uslugom kalkula-
f, tora, prvo ete napraviti posredniku klasu. Da kaem jo jednom, to moete uiniti
Da biste napravili posrednika, upiite wsdl u Visual Studio odzivniku i zatim putanju
do W SDL saetka. Na primjer, moete upisati:
usdl http://localhost:1 9 9 7 5 /CalculatorWS/Service.asmx?wsdl
P r im je r 15-5. P r im je r k l i j e n t s k o g k o d a z a p r i s t u p W eb u s lu z i k a l k u l a t o r a
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
//
// This source code was auto-generated by wsdl, Version=2.0.40607.16.
II
/ / / <remarks/>
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.Des ignerCategoryAtt ribute (" code")]
[System.Web.Services.WebServiceBindingAttribute(Naine="ServiceSoap",
Namespace="http://tempuri.org/)]
{
private System.Threading.SendOrPostCallback AddOperationCompleted;
I I I <remarks/>
public Service() {
384 | Programiranje C#
'primjer 15-5. Primjer klijentskog koda za pristup V/eb usluzi kalkulatora (nastavak)
this.Uri = "http://localhost:19975/CalculatorklS/Service.asmx";
}
I I I <remarks/>
public event AddCompletedEventHandler AddCompleted;
I I I <remarks/>
public event SubCompletedEventHandler SubCompleted;
I I I <remarks/>
public event MultCompletedEventHandler MultCompleted;
/// <remarks/>
public event DivCompletedEventHandler DivCompleted;
I I I <remarks/>
public event PowCompletedEventHandler PowCompleted;
I I I cremarks/>
[System.Web .Services.Protocols.SoapDocumentMethodAttribute
("http: //tempuri.org/Add", RequestNamespace="http://tempuri.org/",
ResponseNamespace="http://tempuri.org/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public double Add(double x, double y) {
object[] results = this.Invoke("Add, new object[] {
i y});
return ((double)(results[o]));
I I I <remarks/>
public System.IAsyncResult BeginAdd(double x, double y, System.AsyncCallback callback,
object asyncState) {
' return this.BeginInvoke("Add", new object[] {
I I I <remarks/>
public double EndAdd(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((double)(results[0]));
}
|| I I I <remarks/>
-( public void AddAsync(double x, double y) {
this.AddAsync(x, y, nuli);
t }
I I I <remarks/>
public void AddAsync(double x, double y, object userState) {
if ((this.AddOperationCompleted == nuli)) {
this.AddCompleted(this,
new AddCompletedEventArgs(invokeArgs.Results,
invokeArgs.Error, invokeArgs.Cancelled,
invokeArgs.UserState));
}
}
I I I <remarks/>
II...
Ovaj kompleksan kod sastavio je W SDL alat za izradu posrednikog DLL-a potrebnog
za izradu klijenta. Datoteka koristi puno atributa, ali sa vaim poznavanjem C# jezika
moete donekle shvatiti kako neki od njih funkcioniraju.
Datoteka poinje deklariranjem S ervicel klase izvedene iz SoapHttpClientProtocol
koja se pojavljuje u imenskom prostoru System.Web.Services.Protocols:
public class Servicel :
System.Web.Services.Protocols.SoapHttpClientProtocol
386 I Programiranje C#
|Kad je to uinjeno, moete pozvati Pow() metodu kao da je to metoda na lokalno
dostupnom objektu:
for (int i = 2;i<i0; i++)
for (int j = l;j <lO;j++)
{
Console.WriteLine(
"{0} to the power of {1 } = {2 }", i, j,
theWebSvc.Pow(i, j));
}
I Ova jednostavna petlja stvara tablicu potencija brojeva od dva do devet, prikazujui
za svakog potencije od jedan do devet. Kompletan izvorni kod i izvadak izlaza prika-
5 anje u primjeru 15-6.
fordrcgior
i namespace CalculatorTest
d
i class Program
I i
|.7/ Program za testiranje Web usluge
public class Tester
{
i public static void Hain()
I {
i. Tester t = new Tester();
t.Run();
}
Izlaz (odlomak):
5 + 7 = 12
2 to the power of 1 = 2
2 to the power of 2 = 4
2 to the power of 3 = 8
2 to the power of 4 =: 16
2 to the power of 5 =: 32
2 to the power of 6 =. 64
2 to the power of 7 =: 12 8
2 to the power of 8 == 256
2 to the power of 9 == 512
3 to the power of 1 == 3
3 to the power of 2 == 9
3 to the power of 3 := 27
3 to the power of 4 := 81
3 to the power of 5 ;= 243
= 72 9
3 to the power of 6 >
3 to the power of 7 = 2187
3 to the power of 8 = 6561
3 to the power of 9 = 19683
388 | Programiranje C#
POGLAVLJE 16
Sastavljanje u cjelinu
U ovom poglavlju ete koristiti mnoge od vjetina koje ste dosad stekli za izradu skupa
integriranih aplikacija. Svrha ovih aplikacija je da na stranicama Amazon.com potrae
relativne rezultate prodaje mojih knjiga o C# jeziku, ASP.NET-u i VB.NET-u.
Ukupni dizajn
Da biste vidjeli kako dvije razliite tehnologije funkcioniraju skupa, napravit ete dvije
neovisne aplikacije (samostalnu aplikaciju klijenta Web usluge i ASP.NET aplikaciju)
povezane preko pozadinske baze podataka. Preciznije, napravit ete stolnu aplikaciju
'H koja uzima podatke od Web usluge s Amazon.com-a i sprema ih u tablicu SQL Server
i baze podataka te ih prikazuje u ASP.NET aplikaciji.
: SQLbaza podataka je vrlo jednostavna. Nazvana je AmazonSalesRanks i sastoji se od
jedne tablice, Booklnfo, kao sto je prikazano na slici 16-1.
Sva polja u ovoj tablici mogu imati vrijednost nula jer ne moete kon-
trolirati koja je informacija dostupna na Amazon.com-u u odreenom
trenutku. Da bi dizajn napravili robustnijim, mogli biste uzeti da ISBN
broj bude primarni klju i da odbacite sve podatke vraene bez ISBN-a.
To je ostavljeno itatelju za vjebu.
389
im Design Table 'Booklnfo' in 'AmazonSale...
Colum n Nam a I D a ta T yp e l l e n g t h i A llow Nulls
char 10 V
title v archa r 500 V
publisher va rc h a r 500 V
p ub D ate v archa r 500 V I
link va rc h a r 1000 V
ra nk in t 4 V
la stU p d a te d a te tim e 8 V 1
te ch n o lo g v va rc h a r 500 V 1
a u th o r va rc h a r 500 V
Colum ns J
D escription
D e f a l t Value
Pracision u
S'.'il
Id e n titv NO
Id e n titv Soed
lc te n titv In cre m erit
Is P.ovvGuid Uo
Form ula
C ollatlon < d a ta b a s e d e fa u lt>
S lika 1 6 -1 . I z r a d a B o o k l n f o t a b l i c e
390 I Programiranje C#
Vaa aplikacija e koristiti ove Web usluge i trebat ete preuzeti skup alata za progra-
mere Amazon Web Services. Tri stvari koje ete trebati su associatesTag (daje ga Ama-
zoni, subscriberID (daje ga Amazon) i odgovarajuu .usdl datoteku (javno dostupna
na Amazon Web Services stranicama).
Dok se uitavaju ISBN brojevi trae se relevantne vrijednosti (naslov, izdava, poloaj)
na Amazon Web stranicama i spremaju se u tablicu baze podataka. Jednostavan pada-
jui popis se tada aurira kako bi se prikazao napredak. Kad su sve knjige unesene,
sustav postaje neaktivan dok ne protekne preostalo vrijeme izmeu sesija. Moete
zapoeti novu sesiju pritiskom na gumba Now. Korisniko suelje je namjerno napra-
vljeno to je mogue jednostavnije.
Primjer 16-2 sadri cijelu aplikaciju iza kojeg slijedi analiza.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
#endregion
namespace AmazonVJebServiceClient
{
partial class AmazonklebServiceClient : Form
{
private int timeRemaining;
const int WaitTime = 900; // 15 minuta
private string connectionString;
private System.Data.SqlClient.SqlConnection connection;
private System.Data.SqlClient.SqlCommand command;
public AmazonWebServiceClient()
{ .
InitializeComponent();
}
private void AmazonWebServiceClient Load( object sender, EventArgs e )
{
// Niz za povezivanje s bazom Sales Rank Database
connectionString =
"server=localhost;Trusted_Connection=true;database=AmazonSalesRanks";
392 I Programiranje C#
primjer 16-2. SalesRankDBWebServices (nastavak)
U Stvara objekt veze i inicijalizira s
// nizom za povezivanje,
connection =
new System.Data.SqlClient.SqlConnection( connectionString );
command.Connection = connection;
timeRemaining = i; // Kad se prvi put pokrene uzima informacije.
UpdateButton();
timeRemaining = 2;
}
if ( updateTimer.Enabled )
txtClock.Text = ( --timeRemaining ).ToString() + " seconds";
else
txtClock.Text = "Stopped";
if ( timeRemaining < l )
{
timeRemaining = WaitTime; // reset the clock
}
}
}
private void GetInfoFromISBN( string isbn, string technology )
if ( isbn.Length != 10 )
return;
394 | Programiranje C#
primjer 16 -2 . SalesRankDBWebServices (nastanak)
int salesRank = -l;
string author = string.Empty;
string pubDate = string.Empty;
string publisher = string.Empty;
string title = string.Empty;
string strURL = string.Empty;
// Aurira popis
string results = title + " by " + author + " +
publisher + ", " + pubDate + ". Rank: salesRank;
IbOutput.Items.Add( results );
lbOutput.Selectedlndex = IbOutput.Items.Count i;
// Aurira bazu podataka
string commandstring = @"Update Booklnfo set isbn = " +
isbn + , title = "' + title + ", publisher = 1,1 +
publisher + pubDate = '" + pubDate + rank = "
salesRank + ", link = + strURL + '", lastUpdate =
System.DateTime.Now + technology = '" +
technology + author = "' +
author + "' where isbn = '" +
isbn +
command.CommandText = commandstring;
try
{
// Ako nijedan red nije promjenjen, ovo je novi zapis
connection.Open();
int numRowsAffected = command.ExecuteNonOuery();
if ( numRowsAffected == o )
command.CommardText - commandString;
command.ExecuteNonOuery();
}
}
catch ( Exception ex )
{
lblStatus.Text = ex.Message;
lbOutput.Items.Add( "Unable to update database!" );
lbOutput.Selectedlndex = lbOutput.Items.Count - 1;
}
finally
{
connection.Close(); // isti
}
} // Zatvoreno za GetlnfoFromlSBN
)
} // Kraj klase
} // Kraj imenskog prostora
command.Connection = connection;
396 I Programiranje C#
;'arijabla timeRemaining je inicijalno postavljena na jednu sekundu, a gumbi su auri-
rani da postave tekst na gumbu Start:
timeRe main ing = i; // Kad se pokrene, uzima informacije.
UpdateButton();
vaki put kad mjera vremena otkuca poziva se u p d a t e T i m e r T i c k metoda. Ako mje-
ra vremena radi (korisnik nije pritisnio Stop) varijabla t i m e R e m a i n i n g se smanjuje za
jedan, a kad padne na nulu, vrijeme je za obradu:
if ( updateTimer.Enabled )
txtClock.Text = ( --timeRemaining ).ToString() + " seconds";
else
txtClock.Text = "Stopped";
if ( timeRemaining < i )
{
Prvi korak je da se mjera vremena postavi na vrijednost WaitTime (konstanta jednaka
|15 minuta) i da se obrade ,xml datoteke:
timeRemaining = WaitTime; // Resetiranje sata
p DataSet BookData = new DataSet();
i try
{
BookData.ReadXml( "aspnet_isbn.xml" );
fStvara se skup podataka u kojem svaki red predstavlja unos u XML datoteci. Kad su
gfnjige uitane, uzimate svaki ISBN i pozivate pomonu metodu GetInfoFromISBN i pro-
||ljeujete joj kao parametar ISBN i tehnologiju11pod kojom e broj biti spremljen u
gpazu podataka:
foreach ( DataRow Book in BookData.Tables[0].Rows )
arvi korak je da osigurate da duljina ISBN-a iznosi tono deset znakova (puna provjera
p i koristila regularan izraz kako bi se osiguralo da ISBN sadri devet cjelobrojnih
Irijednosti iza kojih dolazi ili cjelobrojna vrijednost ili slovo X i onda bi se izvela pro-
Ipera kontrolnog zbroja na ISBN-u (zadnja znamenka je kontrolna vrijednost), ali to
|ostavljeno itatelju za vjebu).
>flmazon.cs datoteka definira vei broj korisnih objekata. U primjeru emo koristiti
NSProductData, ItemLookup i ItemLookupRequest kao i Item objekte i kolekcije. Evo
koraka:
3. U z m i t e I t e m L o o k u p R e s p o n s e objekt.
4. Izdvojite polje Items i iz njega uzm ite prvi objekt (pom ak 0), a to je Items,
5. P o g l edaj te I t e m s v ojst vo t o g I t e m s o b j e k t a a to je polje I t e m s objeka ta.
traili.
SubscriptionID:
lookup.AssociateTag = "libertyassociaOOA ;
lookup.Subscripticnld = "Your ID Here ;
Inicijalizitajte njegovo Request svojstvo da bude polje od jednog objekta i postavite taj
objekt da bude ItemLookupRequest objekt kojeg ste napravili ranije:
lookup.Request = new ItemLookupRequest[l];
lookup.Request[0] = req;
koje se m o g u pojaviti k o d o b r a d e . P o n i t e p o z i v a n j e m I t e m L o o k u p m e t o d e :
info = response.Items[o];
items = info.Item;
item = items[0];
398 I Programiranje C#
|Sad " l02616 P stavitl lokalne varijable da prihvate vrijednosti koje ste uzeli. FixOuotes
j metoda je pomona metoda za pretvaranje jednostrukih navodnika u primljenom nizu
'-znakova tako da ne stvaraju probleme u bazi podataka:
salesRank = item.SalesRank == nuli ? -i : Convert. To I nt32( ite m,Sale sRank);
author - FixOuotes( item.ItemAttributes.Author[o] );
pubDate = FixOuotes(item.ItemAttributes.PublicationDate);
publisher = FixQuotes(item.ItemAttribirtes.Publisher);
title = FixOuotes(item.ItemAttributes.Title);
strURL = item.DetailPageURL;
|Kad imate ove informacije spremni ste aurirati padajui popis i, to je vanije auri-
4 rati bazu podataka.
\Prilikom auriranja baze podataka prvo ete probati Update iskaz. Ako je broj zahvae-
n ih redova jednak nula, red jo ne postoji u bazi podataka pa ete unijeti vrijednosti.
p rik a z iv a n je re z u lta ta
;Ov(!j ptu napraviti emo nove ASP.NET Web stranice AmazonSalesRanks za prikaz infor-
macija koje vraa Amazon. Povucite tri GridView objekta na obrazac, ali ih nemojte
vezivat! s podacima. Uiniti emo to runo. Primjer 16-3 prikazuje kompletnu ,aspx
stranicu, ukljuujui poruku ispisanu iznad tablice, naslove tablica, oznaku zadnjeg
p n ra n ja tpolje za tekst koje se koristi za odluivanje koliko redova e biti prikazano
I;
frim jer 1 6 -3 . P r ik a z iv a n je r ez u lt a t a
400 | Programiranje f#
primjer 16-3. Prikazivanje rezultata (nastavak)
<HeaderTemplate>
Position
</HeaderTemplate>
<ItemTemplate>
<asp:Label Runat="server" ID=Label 2 ">
<%# rowNumber %></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<FleaderTemplate>
Title
</HeaderTemplate>
<ItemTemplate>
<a href = http :// www.amazon.com/exec/obidos/ASIN/<&#
Eval("isbn")%>/" target="_blank"><%# Eval("title") %></a>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText=Author"
ReadOnly="true" DataField=Author" />
<asp:BoundField HeaderText=''Publisher"
ReadOnly=true" DataField="Publisher" />
<asp:BoundField FleaderText=''Publish Date"
ReadOnly="true DataField="pubDate />
<asp:BoundField HeaderText="Rank"
ReadOnly="true" DataField="Rank
DataFormatString="{o:NO}"
ItemStyle-HorizontalAlign="right" h
</Columns>
</asp:GridView>
<br />
<b>VB Titles</b>
<asp:Grid\/iew ID="gvVBNet' Runat="server"
OnRowDataBound="RowDataBound"
AutoGenerateColumns="'false"
1HeaderStyle-BackColor="PapayaWhip"
BorderColor="#000099"
AlternatingRowStyle -BackColor="LightGrey"
HeaderStyle-Font-Bold=true
Width="900">
<Columns>
<asp:TemplateField HeaderStyle-Width ="io">
<FleaderTemplate>
Position
</HeaderTeinplate>
<ItemTemplate>
<asp:Label Runat="server" ID="Label 3 ">
<%# rowNumber fo</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<FleaderTemplate>
Title
</HeaderTemplate>
</columns>
Prvi stupac unutar elementa columns je element predloka stupca. On omoguava da f a*
Naslov (i ostale n i z o v e znakova) trebate provjeriti da vidite ispisuju li
ubacite kontrole u stupac. U prvoj instanci dodat ete Headertemplate (koji se koristi se ispravno.
za izradu zaglavlja stupca) sa tekstom Position i asp:label kontrolom. Ta oznaka ce
Ovaj atribut uzrokuje da se hiperveza otvori u novoj instanci preglednika. Tijelo hiper-
veze (prikazani tekst hiperveze) je takoer evaluirana vrijednost:
Eval("title")
Ako povezani podaci sadre naslov Programming Visual Basic .NET , Second Edition
i ISBN 0596004389 , ova stavka emitira sljedei HTML:
<a href=http://www.amazon.com/exec/obidos/ASIN/0596004389/
targe1:="_ blank">Programming Visual Basic .NET 2 nd Edition </a>
Prva dva stupca su sloenija. Prvi zato stoje potrebno malo truda da se napravi rowNum-
ber (pogledajte sljedei kod), a drugi zato to trebamo umotati povezanu vrijednost
(ISBN i naslov) u hipervezu. Sljedea etiri stupca su jednostavnija zato to su samo
povezani s podacima.
Prvi povezani stupac u zaglavlju ima tekst Author, oznaen je kao read0nly i povezan
je sa stupcem za autore u redu DataSet tablice s kojom je ovaj GridView povezan:
<asp:BoundColumn HeaderText=Author"
ReadOnly="true"
DataField="author"/>
Implementiranje tablice
Kompletan izvorni kod za datoteku s kodom je prikazan u primjeru 16-4, nakon ega
slijedi analiza.
404 | Programiranje C#
primjer 16-4. D atoteka s kodom za SalesDisplay
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using Sy stem.W e b .U l .WebControls.WebParts;
using S yste m .W e b .U I .HtmlControls;
rowNumber = 0;
rowNumber = 0 ;
// txtShowRecords.DataBind();
lblLastUpdate.Text = Last updated: " +
dataSet.Tables [2]. Rows [0] [" lastUpdate" ]. T o S t r i n g O ;
}
void RowDataBound( object sender, GridViewRowEventArgs e )
{
this.rowNumber++;
}
}
Program zapoinje deklariranjem veeg broja lokalnih varijabli, od kojih je najvanija
r o w N u m b e r koja je inicijalizirana na 0:
406 | Programiranje C#
Dalje u metodi za obradu dogaaja uitavanja stranice, uspostavljena je veza s bazom
podataka i baza podataka je pretraena po tehnologiji11 (to jest, ASP.NET ili C # ili
VB.NET):
string connectionString =
"server=localhost;Trusted_Connection=true;database=AmazonSalesRanks";
string commandString =
@"Select top " + shouRecords +
" * from Booklnfo where technology = 'A5PNET' order by rank";
SqlDataAdapter dataAdapter =
new SqlDataAdapter(commandString, connectionString);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet,"aspBookInfo"); // Prva tablica
Isto je uinjeno za sve ostale upite. Kad su napravljene tablice za skup podataka, napra-
vljen je pogled na podatke za prvu tablicu. To je pogled na ASP.NET rezultate:
DataView aspDataView =
dataSet.Tables[0],DefaultView;
Pretraivanje po kategorijama
Pozivanje metode Web usluge za svaki ISBN koji elite provjeriti ni izdaleka nije naju
inkovitiji mogui pristup. Ne samo da to ukljuuje vie slanja i primanja podataka do
Amazona, ve je i vjerojatno da e ISBN brojevi koje stavite na popis zastariti gotovo
istovremeno kad novi konkurenti iziu na trite, a drugi budu rasprodani.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
ftendregion
namespace AmazonWebServiceClient
{
partial class AmazonWebServiceClient : Form
{
private int timeRemaining;
const int WaitTime = 900; // 15 minuta
private string connectionString;
private System.Data.SqlClient.SqlConnection connection;
private System.Data.SqlClient.SqlCommand command;
public AmazonWebServiceClient()
{
InitializeComponent();
}
408 | Programiranje C#
primjer 26-5. SalesRankDBWebServices02 (nastavak)
// Niz za povezivanje s bazom podataka Sales Rank Database
connectionString =
"server=localhost;Trusted_Connection=true;database=AmazonSalesRanks";
command.Connection = connection;
timeRemaining = l; I I Kad se pokrene uzima informacije
UpdateButton();
}
private void btnStart_Click( object sender, EventArgs e )
{
// Ukljuuje mjera vremena
updateTimer.Enabled = updateTimer.Enabled ? false : true;
UpdateButton();
}
private void btnNow_Click( object sender, EventArgs e )
{
timeRemaining = 2;
}
private void UpdateButton()
{
btnStart.Text = updateTimer.Enabled ? "Stop" : "Start";
}
private void updateTimer_Tick( object sender, EventArgs e )
{
if ( updateTimer.Enabled )
txtClock.Text = ( --timeRemaining ).ToString() + " seconds";
else
txtClock.Text = "Stopped";
if ( timeRemaining < 1 )
{
timeRemaining = klaitTime; I I Resetira sat
timeRemaining = klaitTime;
GetInfoFromAmazon( "ASP.NET", "ASPNET" );
GetXnfoFromAmazon( "C#", "CSHARP" );
GetInfoFromAmazon( "VB.NET, "VBNET" );
}
}
}
catch ( System.Exception e )
{
lblStatus.Text = e.Hessage;
}
ItemSearchResponse response;
410 [ Programiranje C#
i primjer 16-5. SalesRankDB\VebServices02 (nastavak)
item.ItemAttributes.PublicationDate);
publisher = FixOuotes( item.ItemAttributes.Publisher );
title = FixOuotes( item.ItemAttributes.Title );
strURL = item.DetailPageURL;
// Aurira polje za tekst
string results = title + " by " + author + ": " +
publisher + ", " + pubOate + . Rank: " + salesRank;
lbOutput.Items.Add( results );
lbOutput.Selectedlndex = lbOutput.Items.Count - l;
command.CommandText = commandString;
try
{
II Ako nijedan red nije promijenjen, ovo je novi zapis
connection.Open();
int numRowsAffected = comand.CxecuteNonOuery();
if ( numRowsAffected -= 0 )
{
commandString = @"Insert into Booklnfo values ('" +
isbn + " , " + title + " , + publisher +
> +
pubDate + "', '" + FixOuotes( strURL ) + "', "
+ salesRank + ", +
System.DateTime.Now +
'" + technology + ", '" + author +
command.CommandText = commandString;
command.ExecuteNonOuery();
}
catch ( Exception ex )
{
lblStatus.Text = ex.Hessage;
lbOutput.Items.Add( "Unable to update database! );
lbOutput.Selectedlndex = lbOutput.Items.Count - l;
finally
{
connection.Close(); // isti
}
Application.DoEvents(); // Aurira korisniko suelje
}
catch ( System.Exception ex)
{
lblStatus.Text = ex.Message;
}
} // Zatvara GetlnfoFromAmazon
}
} // Kraj klase
} // Kraj imenskog prostora
}
Primjetite da je keyword svojstvu dodijeljen proslijeeni keyword parametar (to jest, C#,
A S P . N E T ili V B . N E T ) . Svojstvo Searchlndex ograniava pretraivanje na knjige (radije
nego, na primjer, CD-ove).
Kad je napravljen ItemSearchRequest objekt ugradite ga u ItemSearch objekt koji sadri
AssociateTag i SubscriptionID.
412 | Programiranje C#
__________ DIO III
CLR i .NET kostur
POGLAVLJE 17
:PE datoteke
uSklopovi su na disku Portable Executable (PE) datoteke. PE datoteke nisu novost.
i Format .N ET PE datoteke je isti kao i obinih Windows PE datoteka. PE datoteke se
^implementiraju kao DLL-ovi ili EXE datoteke.
Fiziki, sklopovi se sastoje od jednog ili vie modula (engl. module). Moduli su sastavni
Idijelovi sklopova. Sami za sebe, moduli se ne mogu izvoditi. Moraju biti ukljueni u
l.sklopove da bi bili korisni.
Instalirat ete i iznova upotrijebiti sav sadraj sklopa kao jedinicu. Sklopovi se uita-
|vaju na zahtjev i nee biti uitani ako nisu potrebni.
Metapodaci
|Metapodaci (engl. metadata) su podaci pohranjeni u sklopu koji opisuju tipove i
jpnetode sklopa i pruaju druge korisne informacije o sklopu. Za sklopove se esto
|kae da sami sebe opisuju jer metapodaci potpuno opisuju sadraj svakog modula.
iMetapodaci su deteljno obraeni u osamnaestom poglavlju.
415
Sigurnosna granica
Sklopovi ine sigurnosne granice kao i granice tipa. To jest, sklop je doseg za tipove
koje sadrava, a definicije tipova ne mogu prelaziti izmeu sklopova. Naravno, moete
se pozivati na tipove izvan granica sklopa navoenjem reference traenog sklopa u raz-
vojnom okoliu ili naredbenom redu prilikom prevoenja. Ono to ne moete imati je
definicija tipa koja vai u dva sklopa.
Interni modifikator pristupa ograniava pristup (metodi, na primjer) na trenutni
sklop.
Manifesti
U okviru svojih metapodataka svaki sklop sadri manifest (engl. manifest). On opisuje
to se nalazi u sklopu: podaci za identificiranje (ime, inaica i tako dalje), popis tipova
i resursa u sklopu, popis modula, plan povezivanja javnih tipova s kodom za implemen-
taciju i popis sklopova na koje se poziva ovaj sklop.
ak i najjednostavniji program ima manifest. Moete ga ispitati koritenjem ILDasm
alata koji je dio razvojnog okolia. Kad otvorite manifest s ILDasm alatom, EXE pro-
gram iz primjera 12-3 izgleda kao na slici 17-1.
1
f EventsWithDelegates.exe - R DASM IB u Jg fe l
B V 1____________
MANI FEST
( M P EventsWithDelegates
9 EventsW ithDelegates.Propertles
EventsW ithDelegates.Clock
EventsW fthDelegates.DisplayClock.
EventsW ithDelegates.LogCurrentTime
EventsVflthDelegates.Test
M EventsVVithDelegates.TimelnfoEventArgs
1:
l 1
M
Manifest se nalazi u drugom redu. Ako ga dvaput pritisnete otvara se Manifest prozor
kao na slici 17-2.
Ova datoteka slui kao plan sadraja sklopa. U prvom redu moete vidjeti referenc i
prema sklopu mscorlib na koji se poziva ova, ali i svaka druga .N ET aplikacija, msco
l ib je sklop jezgrene biblioteke za .N ET i dostupan je na svakoj .N ET platformi.
416 | Programiranje C#
Rhd Rnd
RndNert.
// Metaata uersion: u 2 . 0.40607
.assenbly xt rn nscorlib
<
.publickeyt 0ken * (07 70 SC 56 19 34 EQ 89 )
.uer 2: 0:3600:0
>
.assenbly extern Systen
<
,pUt)lickeytOken * (07 70 SC 56 19 34 E O 89 )
.uer 2 : 0: 3600 :0
>assemt>ly EuentsHithOelegateS
{
.custon instance uoid [nscorlib]Systen.Reflection. nssenblyConpanyOttribu:'
.custon instance uoid [nscorlib]Syste.Reflection. OssenblyTradenarkfittri;
.custon instance uoid [nscorlib)Systen.Reflection. OssenblyCopyriyhtOttri
S lika 1 7 -2 . M a n i fe s t p r o z o r
Sljedei red sklopa je referenca na sklop iz primjera 12-3. Moete takoer vidjeti da
se ovaj sklop sastoji od samo jednog modula. Zasad moete zanemariti ostatak meta-
podataka.
P r im j e r 1 7-1. K l a s a F r a c t io n
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace ProgCS
{
public class Fraction
{
private int numerator;
private int denominator;
418 I Programiranje C#
primjetite da je Fraction klasa u ProgCS imenskom prostoru. Puno ime klase je ProgCS.
Fraction.
P r im jer 1 7 -2 . K a l k u l a t o r
using System;
using System.Collections.Generic;
using System.Text;
#endregion
namespace ProgCS
{
public class MyCalc
{
public int Add( int vali, int val 2 )
{
return vali + val2;
}
public int Mult( int vall, int val2 )
{
return vali * val 2 ;
}
}
}
Jo jednom, MyCalc je dosta ogoljena klasa kako bi pojednostavnili primjer. Primjetite
da se i MyCalc takoer nalazi u ProgCS imenskom prostoru.
To je dovoljno za izradu sklopa. Upotrijebite Assemblylnfo.cs datoteku za dodavanje
metapodataka u sklop. Upotreba metapodataka je obraena u poglavlju 18.
Primjer 17-3 prikazuje kompletnu makefile datoteku (koja je odmah nakon toga
detaljno objanjena). Da biste izveli ovaj primjer stavite makefile datoteku (s imenom
makefile ) u mapu zajedno s kopijama datoteka Calc.cs, Fraction.cs i Assemblylnfo.cs.
Pokrenite .N ET naredbeni prozor i pozicionirajte se u tu mapu. Pozovite nmake pro-
gram bez ikakvog modifikatora. \J podmapi\bin ete pronai SharedAssembly.dll.
P r im j e r 1 7 -3 . K o m p l e t n a m a k e f i l e d a t o t e k a z a s k l o p s v i e m o d u l a
ASSEMBLY= MySharedAssembly.dll
BIN=.\bin
SRC=.
DEST=.\bin
MODULETARGET=/t:module
LIBTARGET=/t:library
EXETARGET=/t:exe
REFERENCES=System.dll
MODULES=$(DEST)\Fraction.dll $(DEST)\Calc.dll
METADATA=$(SRC)\AssemblyInfo.cs
ali: $(DEST)\MySharedAssembly.dll
# Add Fraction
$(DEST)\Fraction.dll: Fraction.cs $(DEST)
$(CSC) $(MODULETARGET) / r :$(REFERENCES: =;) /out:$@ %s
$(D EST) ::
!if !EXISTS($(DEST))
mkdir $(DEST)
lendif
420 | Programiranje C#
Zatim se zadaju mape koje ete koristiti - izlaz se smjeta u bin podmapi'U trenutne
niape a izvorni kod uzima iz trenutne mape:
SRO.
DEST=Abin
Naredbeni red stvara biblioteku i dodaje joj module, smjetajui izlaz u datoteku
MySharedAssembly.dll:
$(DEST)\$(ASSEMBLY): $(m et a dat a ) $(mod ul es ) $(DEST)
5(CSC) S(LIBTARCET) /addmodule:$(MODULES: =;) /out:$@ %s
Da biste ovo postigli, nmake program mora znati kako da napravi module. Prvo upu-
tite nmake program kako da napravi Calc.dll. Za to trebate izvorni kod Calc.cs. Zadajte
programu nmake sljedeu naredbu da napravi DLL:
$(DEST)\Calc.dll: Calc.cs $(DEST)
$(CSC) $(MODULETARGET) /r :$(REFERENCES: =;) /out:$@ %s
Rezultat izvoenja programa nmake s ovom makefile datotekom su tri DLL datoteke:
Fraction.dll, Calc.dll i MySharedAssembly.dll. Ako otvorite MySharedAssembly.dll s
ILDasm alatom, vidjet ete da sadri samo manifest, kao na slici 17-3.
.pub
pubUcfcegtaite (87
.urr 7: 0: 3600:8
jss*wi>ly Hji
Hjisnarcafls
flsit01
01ii ii)
sssi i Si! - ! jj j; I
:SiSSE Si! S|
SS .SSS Si! < S
;rS!!:=T!SS5!SiSli--
.ltugebase 8x80600900
Fil Ugneiit 0x 00060200
's t* th r strv e 0x00188000
.subsusteft 0x8003 U H1K00WS_CU1
c a rd a gs 0x00080081 // U.0HI.V
// |nage base: 8x 06240000
S l i k a 17-4. M a n i fe st z a M y S h a r e d A s s e m b l y .d l l
Prvo vidite vanjski sklop za jezgrenu biblioteku (mscorlib), nakon koje slijede dva
modula, ProgCS.Fraction i ProgCS.myCalc.
Sad imate sklop koji se sastoji od tri DLL datoteke: MySharedAssembly.dll s manife-
stom i Calc.dll i Fraction.dll s potrebnim tipovima i implementacijama.
Ispitivanje sklopa
Da biste koristili ove module napravit ete upravljaki program. To je prikazano u pri -
mjeru 17-4. Spremite ovaj program kao Test.cs u istoj mapi s ostalim modulima.
P r im je r 1 7 - 4 . U p r a v l ja k i p r o g r a m z a i s p it iv a n je m o d u l a
namespace Progxamming_CSharp
1
using System;
422 | Programiranje C#
p r im je r 17-4. U p r a v l ja k i p r o g r a m za is p it iv a n je m o d u la ( n a s t a v a k )
Uitavanje sklopa
Sklop se uitava u aplikaciju koritenjem AssemblyResolver u procesu koji se zove ispi-
tivanje (engl. probing). Unutar .N ET kostura Assembiy Resolver se automatski poziva
i ne trebate ga eksplicitno pozvati. Njegov posao je da uita program.
Postavite toku prekida u drugom redu Main() metode, kao to je prikazano na slici
17-5.
Prekinite izvoenje kod toke prekida i otvorite prozor Modules. Samo dva modula su
uitana, kao to je prikazano na slici 17-6.
8.0. 4060..
060...
... 7/25/
25/2004
2004 9:06 ...
C :\W lfC O WS\as$emUy\GAC^M.
; 0 v s t o s t u tid 2.0. 4060..
060...
... 7/7/2004 7:04 PM
C:\WIHDOWS\$ambt>W9.C _M..
'l a Syt
ytam.Wr<Jowr<Jows.Ft*fre.dl 2.0. 4060
4060...
60...7
...7/7/2004 7:04 PM
C:\WINDOW S\assent4y\6AC_M.
|0 System. 2.0. 4060
4060..
60...
... 7/7/2004 7:04 PM
>i3 Syji
Syjiem.
em.[>avr avrtio.< C:\V4lN D C W S\*ent*)r\GACJ 4. 8.0.4060
4060..
60...
... 6/25/
25/2004
2004 6:09 PM
0 M od J& T ettOriv a-r th o it.e a C:\D o Ctm entj and SettrQi\JdS- 2.0. 4060
4060...
... 7/7/2004 7:04 PM
C :AW U C O W S\aueny \W C 3 .. 2.0. 4060
4060...
60...7
...7/7/2004 7.04 PM
i a Sy*lwn.Oota.<*
C:lWlNDO
NDOWS\aem
aemtty\GACGAC-J*.J*.
: a S n te n .M i C A O ocurenls a rd SeC. 1.0. V691
691... 6/78/78/2004
004 4:05 PM
! 0 M od J e T tD rl* er exa C :\D oam 0rUs and s e t t in ^ J .
I .................. ..... m
j________ _ -
p-ftothietcsmrtvet.t>\_ __
'
_
"rojujmcr dxefccti.veij
Onatnespoce H oduleTestD elv et
lo n d t n e a n o r e d M a e n ia l?
f e a t t - ne T e * t ( ) ;
:l t.U s e C S ( ) ;
C .U s e F ra e tlo o O ;
... gji^
---- Ako Test.cs niste razvili kao dio Visual Studio .NET rjeenja, pozovite
**, Svstem.Diagnostics .Debugger. Launch() metodu malo prije drugog reda
'V d , u HainQ metodi. To omoguava da odaberete program za otkrivanje
pogreaka koji elite koristiti (obavezno prevedite Test.cs koritenjem
opcija /debug i /r: HySharedAssembly.dll).
424 I Programiranje C#
tttkias ' - 9X
N*e Patti Hi Cocto Sym M Statut Vaston Ttrestacrp
J]crseorlb.dl C :VW b 3 w ^ W *efT \6 :J . . . v' No N oirtrD cfebj... 2.0. 7/7/2004 74.-00646H..'H !
iivttiMtuUd CAWWOO'NS\ttr**>\GfeC _M... y No No vytrfccfe ba. . ... 7/25/2004 9:06...
eo.roeo..
eo...
tt)System.Wndow.Forni5.<* C:^wi>cOWS\siint*r\GaC_M... V No N a ir o to b lN .. 2.0. 7/7/2004 7:044060...PM I
111Sfilem.di C.\W lM 30W \*!n*#\GAC J^... Yes No Novytrfcctsbe... j.a-1060... 7/7/2004 7;04 fW ;
ij)Systern-C*Jwhp3.c# C ;\W W X>*S\*!errtt*ViAi:,J4... r N> NonrrC ohbe... 2.0. 7/7/2004 7.044060P.M I
li)ldieTeitnnr.vtf>I.cir r A / t a ii r m u and SW *js\Xft... y No H0 5yoW5fca... 6 0.4060. 6/25/2004 6:00 fM ;
ii) SvflemCMiJ.iJ C:\WffC Ow S\ierrt*r\GAC 3... v No Ud t r o t * * toa.. 2.0. 7/7/2004 7:044060.P.t
!*)Syitem.xrrt.ci C;VW
MDOW
S\KrttAGAC>t- Y i-e Nos/otJdstea..
ea...
... 2.0.4060... 7/7/2004 7:04 PM 1
C:\0txi*iw iU andSette>0rtJM... No S y otrtbaded. C\Gotisnents4ndSctu.. 9 1.0. 1691.... 8/10/20044.051*41
C:\DocumenU and SetthQS\M ... No Y 5y<rtHb toadcA. C I O c c u m ii ard 1.0.1691.... 6/16/2004 3:54 PM)
C:\Occtm eritt and Settr^sUes... No V StTr**4t kuded. c :\P o as ne ntm ) Seta... u 6/10/2004 3.-S4 PM i
.- MocMeTtitDrtecr.cs [
1/M xifeT ettC*tve<.Tt
Pi'og
Pi'ogCs.c
Cs.cvc&lo c a lc < ne Pr oo CS .yC l oI)
Can
Ca n cole. W titeL
teLlne ( -J * s - (Q|Xnl*S c 11
c alc .Addt
ddt 3, S 1 , c a lc .H U le f 3 , S 1
Privatni sklopovi
I ; Sklopovi mogu biti privatni (engl. private)i dijeljeni (engl. shared). Privatni sklopovi su
1 namijenjeni za koritenje u samo jednoj aplikaciji. Dijeljeni sklopovi su namijenjeni za
| upotrebu izmeu vie aplikacija.
| Svi sklopovi koje ste dosad napravili su privatni. Kad prevodite aplikaciju podrazumi-
t jeva se da je napravljen privatni sklop. Sve datoteke za privatni sklop se uvaju u istoj
i mapi (ili u stablu podmapa). To stablo mapa je odvojeno od ostatka sustava, jer nita
H drugo osim jedne aplikacije ne ovisi o njenom sadraju i moete jednostavno prebaciti
ovu aplikaciju na drugo raunalo tako da kopirate mapu i podmape.
fiPrivatni sklop moe imati bilo koje ime koje odaberete. Nije vano ako se to ime kosi
. sa imenima sklopova u drugim aplikacijama. Imena su lokalna za aplikaciju.
Ranije su se prilikom instaliranja DLL-ova na raunalu (COM DLL-ova) unosili zapisi
u Registry. Bilo je teko izbjei oneienje registra beskorisnim zapisima. U svakom
sluaju, ponovna instalacija programa'na drugom raunalu nije bila trivijalna. Od
kada se koriste sklopovi nita od toga vie ne vai. S privatnim sklopovima, instalira-
n je postaje jednostavno kao kopiranje datoteka u odgovarajuu mapu.
Dijeljeni sklopovi
Moete napraviti sklopove koje e dijeliti vie aplikacija. To e vam moda biti potrebno
jako napiete opu kontrolu ili klasu koju mogu koristiti drugi projektanti. Ako elite
(dijeliti sklop, on mora zadovoljiti odreene uvjete.
(Prvo, sklop mora imati jako ime (engl. strong name). Jaka imena su globalno jedinstvena.
Drugo, dijeljeni sklop mora biti zatien od novijih inaica, tako da svaka nova inaica
koju objavite mora imati novi broj inaice.
Konano, da biste dijelili sklop, stavite ga u Global Assembly Cache (GAC). Ovo je
podruje sustava datoteka koje CLR rezervira za uvanje dijeljenih sklopova.
Inaice
Dijeljeni sklopovi u .NET-u su jedinstveno identificirani preko imena i inaice. GAC
omoguava da starije inaice sklopa budu dostupne zajedno uz noviju inaicu.
Broj inaice sklopa moe izgledati ovako: 1 : 0 : 2 2 0 4 : 2 1 (etiri broja odijeljena dvoto-
kama). Prva dva broja (.1:0) su oznake inaice i podinaice, trei broj je izgradnja, a
etvrti (21) je prepravka.
Kad dva sklopa imaju razliite glavne ili sporedne brojeve inaice, onda se obino
smatraju nekompatibilnim. Ako imaju razliite brojeve izgradnje, onda mogu, ali ne
moraju biti kompatibilni, a ako imaju razliite brojeve revizije, onda se smatraju defi-
nitivno kompatibilnim. To izvrsno zvui u teoriji, ali CLR Assembly Resolver ignorira
ovo pravilo i slui samo da podsjeti projektanta, pa se ne namee prilikom izvoenja.
426 | Programiranje C#
jaka imena
Da biste koristili dijeljene sklopove, morate zadovoljiti dva zahtjeva:
Morate moi tono zadati koji sklop elite uitati.
Morate osigurati da sklop nije neovlateno mijenjan i da je sklop koji se uita auto-
riziran od stvarnog tvorca tog sklopa. Da biste to uinili, sklop treba digitalni
potpis prilikom izrade.
Oba ova zahtjeva su zadovoljena koritenjem jakih imena. Jaka imena moraju biti glo-
balno jedinstvena i koristiti javni klju za ifriranje. Jako ime je niz heksadecimalnih
znamenki i ljudima je teko za itanje.
Da bi napravili jako ime, generira se par kljueva (jedan privatni i jedan javni) za jedan
ili vie sklopova. Kombinacija je napravljena od imena i sadraja datoteka u sklopu
i onda ifrirana s privatnim kljuem za sklop. Oznaka javnog kljua (kombinacija
cijelog kljua od osam bajtova) je smjetena u manifest zajedno s javnim kljuem. Taj
postupak se zove potpisivanje sklopa.
ifriranjejavnog kljua
Jaka imena su utemeljena na tehnologiji ifriranja javnim kljuem. Bit ifriranja jav-
nim kljuem je da se naprave dva kljua. Podaci ifrirani prvim kljuem mogu biti
deifrirani samo s drugim. Podaci ifrirani s drugim kljuem mogu biti deifrirani
samo s prvim.
Razdijelite prvi klju kao javni klju kojeg bilo tko moe imati. uvajte drugi klju kao
privatni klju tako da nitko osim vas nema pristup.
Reciprona veza izmeu kljueva omoguava bilo kome da ifrira podatke vaim jav-
nim kljuem i onda moete deifrirati te podatke koritenjem privatnog kljua. Nitko
drugi nema pristup podacima nakon to su ifrirani, ukljuujui osobu koja ih je
ifrirala.
Slino, moete ifrirati podatke vaim privatnim kljuem i onda bilo tko moe dei-
frirati podatke s javnim kljuem, lako ovo znai da su podaci otvoreno dostupni, to
jami da ste samo vi mogli stvorili te podatke. Ovo se zove digitalni potpis.
Kad aplikacija uita sklop, CLR koristi javni klju za dekodiranje kombinacije dato-
teka iz sklopa kako bi se osiguralo da datoteke nisu neovlateno mijenjane. Time se
ujedno sprjeava da se ime kosi s imenima drugih sklopova.
Jako ime moete napraviti koritenjem sn pomonog programa:
sn -k c:\myStrongName.snk
Zastavica -k pokazuje da elite novi par kljueva upisan u navedenu datoteku. Moete
nazvati datoteku kako elite. Zapamtite, jako ime je niz bajtova i nije namijenjeno da
ga ljudi itaju.
Atributi su detaljno obraeni u poglavlju 18. Zasad, moete staviti ovaj kod na vrh
datoteke da povee jako ime koje ste napravili s vaim sklopom.
Sad kopirajte DLL-ove u stablo mapa upravljakog programa, pokrenite ponovno pro-
gram i ovaj put bi trebali vidjeti da radi kako treba.
Pretvorimo MySharedAssembly u dijeljeni sklop. To se izvodi u dva koraka. Prvo, napra-
vite jako ime za sklop i onda stavite sklop u GAC.
428 | Programiranje C#
sn -k keyFile.snk
Jflo postavlja datoteku kljua za sklop. Ponovno napravite sklop s istom makefile datote-
|kom kao ranije i onda otvorite rezultirajui DLL u ILDasm alatu i pogledajte manifest.
);Jrebali biste vidjeti javni klju, kao to je prikazano na slici 17-8.
r .publickey (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00
00 24 00 00 b2 b3 41 31 00 04 00 00 01 00 01 00 .$ ..RSA1
11 13 95 3C 41 19 2B 41 28 29 E8 AF DE 8C A2 04
88 22 BD 4F A9 E1 FS 57 2C 2DE2 43 CF C3 68 4E . .0.. u'- C
F7 C7 72 E8 55 94 8b 11 KA 66 30 F6 D4 22 DB OD . -r.O fO
6E D8 A OD bD 58 28 10 E9 75 D8 BF CC 82 2A EB
04 19 D5 Cl 88 B0 C
20 8F 9B DC 29 AC 46F A
D5 CB 6 SC 58 43 08 ODE9
3 CD 87 3C F8 92 7A 84 \XC
E3 47 84 AD 58 73 3E OD AD 71A
DC0 A2 FA 15 14 A3
G,.Vs>.
88 17 01 AC F3 A3 7AF8 59 BC 3A 16 CB AB 34 cs ........ z.Y.;.. 4.
ImiSlika 17-8. Manifest datoteke MySharedAssembly.dll
Dodavanjem jakog imena potpisali ste ovaj sklop (tone vrijednosti e biti drugaije
jtehego na slici). Da bi pokazali da imena iz GAC-a i reference u klijentovom manifestu
^odgovaraju, htjet ete uzeti jako ime iz DLL-a. Da biste to uinili, pozicionirajte se u
fpmapu u kojoj se nalazi DLL i unesite sljedee u odzivniku:
siv
sn -T MySharedAssembly.dll
|Ova vrijednost je skraena vrijednost javnog kljua za taj sklop koja se naziva oznaka
javnog kljua (engl. public key token).
Kad je to obavljeno, imate dijeljeni sklop kojem moe pristupiti bilo koji klijent. Obnovite
klijent tako to ete ga ponovno napraviti i pogledati njegov manifest, kao na slici 17-10.
430 I Programiranje C#
POGLAVLJE 18
Atributi i refleksija
Diljem ove knjige, naglaavao sam da .NET aplikacija sadri kod, podatke i metapo-
|datke. Metapodaci predstavljaju informacije o podacima, to jest, informacije o tipo-
vima, kodu, sklopovima i tako dalje, koje su pohranjene zajedno s programom. Ovo
rnpoglavlje prouava kako nastaju neki od tih metapodataka i kako se upotrebljavaju.
|Atributi (engl. attributes) predstavljaju mehanizam za dodavanje metapodataka, kao
to su instrukcije prevoditelju i drugi podaci o vaim podacima, metodama, klasama
j samom programu. Atributi se umeu u metapodatke i vidljivi su s pomou alata
S|;BLDasm i drugih alata za itanje metapodataka.
| Refleksija (engl. reflecetion) je proces kojim program moe itati svoje metapodatke ili
metapodatke drugog programa. Kae se da program odraava sebe ili neki drugi pro-
igram izvlaei metapodatke iz odraenog sklopa i koristei ih da informira korisnika
|ili promijeni ponaanje programa.
Atributi
r
JAtribut je objekt koji predstavlja podatke koje elite povezati s nekim elementom u
forogramu. Element kojem dodajete atribut predstavlja cilj (engl. target) atributa. Na
pprimjer, atribut:
[NoIDispatch]
l je povezan s klasom ili sueljem da ukae kako bi ciljna klasa trebala izvoditi iz
|IUnknown a ne iz IDispatch prilikom izvoenja u COM. Programiranje COM suelja je
E,detaljno obraeno u poglavlju 22.
|U poglavlju 17 vidjeli ste ovaj atribut:
[assembly: AssemblyKeyFile("c:\\myStrongName.key")]
431
Time se umeu metapodaci u sklop da zadaju jako ime programa.-
Atributi
Neki atributi su prueni kao dio CLR-a ili kostura. Pored njih moete napraviti i atri-
bute koji su prilagoeni vaim potrebama.
Veina programera e koristiti atribute koje prua kostur, iako izrada vlastitih atributa
$
moe biti moan alat kad se kombinira s refleksijom. To je opisano kasnije u ovom
poglavlju.
2
Ciljevi atributa
Ako pogledate u CLR vidjet ete veliki broj atributa. Neki atributi se primjenjuju na I
sklop, drugi na klasu ili suelje, a neki, kao [VJebMethod], na lanove klase. Ovi objekti ?
predstavljaju ciljeve atributa. Mogui atributi su deklarirani u AttributeTargets enu- 1
meraciji i detaljno su opisani u tablici 18-1. i
Im e lana U p o tre b a
A li Prim jenjuje se na jed a n od sljedeih elem en ata: sklop, klasa, konstruktor, delegat, enumeracija,
dogaaj, polje, suelje, m etod a, m odu l, p aram etar, povratna vrijednost ili struktura
Atribut sklopa zapravo obavlja vie od samog umetanja metapodataka. C# prevoditelj pazi na ovaj atri-
but (kao i na neke druge) koji izaziva poseban nain rada. U ovom sluaju, ita klju datoteke i koristi taj
klju za digitalni potpis sklopa. Obino, meutim, atributi su samo statiki metapodaci koje se umee u
sklop.
432 | Programiranje C#
primjena atributa
primjenite atribute na njihove ciljeve stavljanjem u uglate zagrade odmah ispred cilj-
anog elementa (osim u sluaju sklopova, kad ih stavljate na poetak datoteke).
'S'iV' Mnogi atributi se koriste za meudjelovanje s COM-om, o emu emo detaljnije govo-
riti u poglavlju 22. Ve ste vidjeli primjenu jednog atributa ([WebMethod]) u poglavlju
16. Vidjet ete i upotrebu drugih atributa, kao sto je [Serializable] iz poglavlja 19.
System.Reflection imenski prostor stavlja na raspolaganje vei broj atributa, ukljuujui
atribute za sklopove (kao sto je AssemblyKeyFileAttribute), konfiguriranje te atribute
za inaice. Jedan od atributa s kojim ete se najee susretati u svakodnevnom C#
programiranju (osim ako ne radite s COM modelom) je [S erializable]. Kao to ete
vidjeti u poglavlju 19, sve to trebate napraviti kako biste osigurali da klasa moe biti
serijalizirana na disk ili na Internet je dodavanje atributa [Serializable] klasi:
[Serializable]
class MySerializableClass
.tijlv1Oznaka atributa se stavlja u uglate zagrade odmah prije cilja atributa, a u ovom sluaju
to je deklaracija klase.
I Kljuna injenica o atributima je da znate kad su vam potrebni. Zadatak koji trebate
W iobaviti diktirat e njihovu upotrebu.
#
Prilagoeni atributi
Moete napraviti atribute koji su prilagoeni vaim potrebama te ih koristiti prilikom
izvoenja kako vam odgovara. Pretpostavite, na primjer, da va odjel eli voditi evi-
denciju o ispravljenim pogrekama. Ve imate bazu podataka o svim pogrekama, ali
biste htjeli povezati svaki izvjetaj o pogreci s odreenim ispravkom u kodu.
Mogli biste dodati komentare u kod:
// Pogreka 3 2 3 . Ispravio lesse Liberty 1/1/2005.
To biste lako uoili u izvornom kodu, ali ne postoji veza prema pogreci 323 u bazi
podataka. Prilagoeni atribut bi mogao biti upravo ono to traite. Zamijenili biste
komentar s neim kao to je ovo:
i
Poglavlje 18: Atributi i refleksija | 433
[BugFixAttribute(323,"lesse Liberty ,1/1/2005",
Comment="3edna manje")]
Onda biste mogli napisati program da ita metapodatke, nae ova zabiljekeo ispra
vljenoj pogreci te da aurira bazu podataka. Atribut bi imao ulogu komentara ali
bi takoer omoguavao da programski pribavite podatke s pomou alata koje biste
sami napisali.
.
a
Ovo je. m oda neprirodan prim jer jerb i atributi bili prevedeni u finalni
kod za isporu ku .
.A*
Deklariranje atributa
Atributi, kao i veina drugih stvari u C# jeziku, su ukljueni u klase. Da biste napra-
vili prilagoeni atribut izvedite novu prilagoenu klasu atributa iz System.Attribute-
public class BugFixAttribute : System.Attribute
Trebate uputiti prevoditelja s kojim elementima ovaj atribut moe biti upotrijebljen (tj.
trebate zadati cilj atributa). To zadajte (s im drugim nego) atributom:
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
Imenovanje atributa
Novi prilagoeni atribut u ovom primjeru je nazvan BugFixAttribute. Uobiajeno je
dodati rije attribute imenu atributa. Prevoditelj to podrava tako to dozvoljava da
nazovete atribut skraenim imenom. Prema tome, moete napisati:
[BugFix(l23, "lesse Liberty", "01/01/05", Comment="3edna manje")]
Prevoditelj e prvo potraiti atribut BugFix te, ako ga ne pronae, potrait e BugFix-
Attribute.
Konstruiranje atributa
Atributi uzimaju dva tipa parametara: pozicijske i imenske. U BugFix primjeru, pro-
gramerovo ime, identifikator pogreke i datum su pozicijski parametri, a komentar
434 | Programiranje C#
|fe imenski parametar. Pozicijski parametri se prosljeuju kroz konstruktor po redosli-
Ijedu deklariranom u konstruktoru:
public BugFixAttribute(int buglD, string programmer,
string date)
{
this.buglD = buglD;
this.programiner = programmer;
this.date = date;
}
Ijmenovani parametri su implementirani kao polja ili kao svojstva:
public string Comment
{
get
{
return comment;
i
set
{
comment = value;
}
}
RUobiajeno je za pozicijske parametre napraviti svojstva samo za itanje:
public int BuglD
{
get
{
return buglD;
}
}
Upotreba atributa
gptKad ste definirali atribut moete ga poeti koristiti tako to ete ga staviti odmah
|ispred cilja. Kako biste testirali BugFixAttribute iz prethodnog primjera, sljedei pro-
igram stvara jednostavnu klasu MyMath i dodjeljuje joj dvije metode. Dodijelite BugFixAt-
. tributes atribut klasi za biljeenje povijesti odravanja koda:
[BugFixAttribute(l 2 1 ,"Desse Liberty","01/03/05")]
[BugFixAttribute(l07/Desse Liberty", "01/04/05",
Comment="Fixed off by one errors'!)]
public class MyMath
' Ovi atributi se pohranjuju s metapodacima. Primjer 18-1 prikazuje kompletan program.
If using System;
k ,using System.Collections.Ceneric;
Ejlusing System.Text;
ttendregion
namespace CustomAttributes
{
// Stvara prilagoeni atribut koji e biti dodijeljen lanu klase
[AttributeUsage( AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true )]
public class BugFixAttribute : System.Attribute
{
// Konstruktor atributa za
// pozicijske parametre
public BugFixAttribute
( int buglD,
string programmer,
string date )
{
this.buglD = buglD;
this.programmer = programmer;
this.date = date;
}
// Pristupnik
public int BuglD
{
get
{
return buglD;
}
}
// Svojstvo za imenovani parametar
public string Comment
{
get
{ .
return comment;
}
set
{
comment = value;
}
}
436 | Programiranje C#
Primjer 18-1. R ads prilagoenim atributima (nastavak)
II Pristupnik
public string Date
{
|:S get
{
return date;
}
}
II Pristupnik
Kao to moete vidjeti, atributi nemaju nikakvog utjecaja na izlaz programa. Zapravo,
1 u ovom trenutku imate samo moju rije da atributi uope postoje. Brzi pogled na
metapodatke koritenjem ILDasm alata otkriva da su atributi ipak na svom mjestu
f C:\
C:\Ooc
Oocume
uments and Settings
Settings\Jesse\My D ocum ent
en tsVW ordD ocum e ...
...
F lle V ie w H elp
MANIFEST
9 C u s to m A ttrib u te s
ff 9 C u s to m A ttrib u te s ,P ro p e rtie s
ft C u s to m A ttrib u te s .B u g F ix A ttrib u te
.da ss public a u to ansi b e fo rtfifc ld in it
e x te n d s [rn s c o r lib ]S y s te m .A ttrib u te
| .cus tom in s ta n c e v o id [m s c o riib 3 S y s te m .A ttr ib u te U s a g e A ttr ib u te :: .c to r ( v a lu e ty p e [m s c o rlib ]S y s te m .A ttrib u te T a ro e ts ,i =
v b u g lD : p r iv a te in t3 2
v c o m r r ie n t: p r iv a te s trin g
v d a te : p r iv a te s tr in g
v p ro g ra m m e r : p r iv a te s tr in g
B9 . c t o r : v o id ( in t3 2 ,s tr in g ,s tr in g )
9 g e t _ 8 u g ID : in t3 2 ( )
9 g e t_ C o m m e n t: s tr in g ( )
R I g e t_ D a te : s tr in g ( )
S I g e t_ P ro g ra m n ie r : s tr in g ( ) S
i . v b ld fc tr in g )
A B u glD : in s ta n c e in t3 2 ( )
A C o m m e n t: in s ta n c e s trin g O
A D a te : in s ta nc e s trin g O
A P ro g ra m m e r : in s ta n c e s trin g O
ft C u s to m A ttrib u te s .M y M a th
.d a s s public a u to ansi b e fo re fie ld in it
.c u sto m in s ta n c e v o id C u s to m A ttrib u te s .B u g F ix A ttrib u te :: .c to r (in t3 2 , ...
.cus tom in s ta n c e v o id C u s to m A t t r ib u te s . B u g F ix A tt r ib u te : :. c to r ( in t3 2 , . ..
E3 . c t o r :v o id ()
9 D o F u n d : flo a t 6 4 ( f lo a t 6 4 )
9 D o F u n c 2 : flo a t 6 4 ( f lo a t 6 4 )
C u s to m A ttrib u te s .T e s te r
.d a s s public a u to ans i b e fo re fie ld in it
9 . c t o r : v o id ()
M a in ; v o id ()
.a ss em b ly C u s to m A ttrib u te s
i
i . v e r 1 :0 :1 6 9 1 :2 7 5 3 1
[\
S l i k a 1 8 -1 . M e t a p o d a c i u s k l o p u
Refleksija
Da bi atributi u metapodacima bili korisni trebate nain da im pristupite, a idealno
bi bilo da im pristupate prilikom izvoenja. Klase u imenskom prostoru Reflection
zajedno sa System.Type klasom osiguravaju podrku za ispitivanje metapodataka i rad
s njima.
Refleksija se openito koristi za sljedea etiri zadatka.
438 | Programiranje C#
Pregledavanje m e ta p od a tak a
Mogu ga koristiti alati i pomoni programi koji ele prikazati metapodatke.
i Otkrivanje tipova
Omoguava da ispitate tipove u sklopu te da s njima radite ili da ih instancirate.
To moe biti korisno prilikom izrade prilagoenih skripti. Na primjer, mogli biste
omoguiti korisnicima da meudjeluju s programom koritenjem skriptnog jezika
kao to je JavaScript ili neki novi jezik koji ste sami smislili.
Kasno p oveziv anje s m etod am a i svojstvim a
Omoguava progameru da pozove svojstva i metode na objektima koji su dina-
miki distancirani uz upotrebu otkrivanja tipova. Ovo se naziva i dinamiko pozi-
vanje (engl. d y nam ical invocation).
Stvaranje tipova p rilikom izv oenja
Najekstremnija upotreba refleksije je izrada novih tipova tijekom izvoenja i nji-
hova upotreba za izvoenje zadataka. To biste mogli koristiti kada se prilagoena
klasa napravljena za vrijeme izvoenja izvodi bre nego openitiji kod napravljen
prilikom prevoenja.
Pregled metapodataka
(J ovom dijelu upotrijebit ete C# podrku za refleksiju da biste uitali metapodatke
iz MyMath klase.
Pozovite typeof operator na tip MyMath koji e vratiti objekt tipa Type koji izvodi iz
Memberlnfo.
#4
Klasa Type je srce klasa refleksije. Type uahuruje reprezentaciju tipa
objekta. Ta klasa je primarni nain za pristupanje metapodacima. Type
izvodi iz Memberlnfo te uahuruje informacije o lanovima klase (meto-
dama, svojstvima, poljima, dogaajima i tako dalje).
Sad moete iterirati kroz polje i ispisati svojstva BugFixAttribute objekta. Primjer 18-2
zamjenjuje Tester klasu iz primjera 18-1.
O tk riv a n je tip o v a
Refleksiju moete koristiti za istraivanje sadraja sklopa. Moete pronai tipove pri-
druene modulu; metode, polja, svojstva, dogaaje pridruene tipu kao i potpise svih
metoda tipa, suelja koja tip podrava i osnovnu klasu tipa.
Da biste poeli, dinamiki uitajte sklop koritenjem Assembly. Load() statike metode.
Klasa Assembly za potrebe refleksije uahuruje sam sklop. Jed an od potpisa Load
metode je:
public static Assembly.Load(AssemblyName)
Kad je sklop uitan moete pozvati GetTypes() da vratite polje Type objekata. Objekt
Type je kljuni dio refleksije. Type predstavlja deklaracije tipa (klase, suelja, polja,
vrijednosti i enumeracije):
Type[] types = a.GetTypes();
440 | Programiranje C#
Sklop vraa polje tipova koje moete prikazati u foreach petlji, kao to je prikazano u
primjeru 18-3. Kako ovaj primjer koristi klasu Type, trebat ete dodati direktivu using
za imenski prostor System.Reflection.
P rim jer 1 8 -3 . R e f le k s i j a s k lo p a
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
ttcndregion
namespace ReflectingAnAssembly
{
public class Tester
{
public static void Main()
{
// to je u sklopu
Assembly a = Assembly.Load( "Mscorlib1' );
Type[] types = a.GetTypes();
foreach ( Type t in types )
{
Console.WriteLine( "Type is {o}", t );
}
Console.WriteLine(
"{0 } types found", types.Length );
}
}
}
Izlaz ovog programa bi popunio mnogo stranica pa ga neu cijelog navoditi. Evo krat-
kog odlomka:
Type is Systera.Object
Type is ThisAssembly
Type is AssemblyRef
Type is System.ICloneable
Type is System.Collections.IEnumerable
Type is System.Collections.ICollection
Type is System.Collections.IList
Type is 5ystem.Array
2373 types found
Ovaj primjer je dao polje s tipovima iz jezgrene biblioteke i ispisao ih jedan po jedan.
Polje je u mom raunalu sadravalo 2373 unosa.
U inaici 1.1 sam u svom raunalu naao 1426 unosa. Deki iz M icro-
softa su bili vrijedni!
A*
_ _ >,'
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
#endregion
namespace ReflectingOnAType
{
public class Tester
{
public static void Main()
{
// Ispitivanje tipa
Type theType =
Type.GetType(
"System.Reflection.Assembly" );
Console.WriteLine(
"\nSingle Type is {o}\n", theType );
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
#endregion
namespace ReflectingOnMembersOfAType
{
public class Tester
{
public static void Main()
442 | Programiranje C#
'ipritnjer 18-5. Refleksija lanova tipa (nastavak)
{
// Ispitivanje objekta
Type theType =
Type.GetType(
"System.Reflection.Assembly" );
Console.WriteLine(
\nSingle Type is {0 }\n", theType );
}
Jo jednom, izlaz je prilino dug, ali u izlazu ete vidjeti polja, metode, konstruktore
i svojstva kao u ovom odlomku:
System.Type GetType(System.String, Boolean, Boolean) is a Method
System.Type[] GetExportedTypes() is a Method
System.Reflection.Module GetModule(System.String) is a Method
;|! System.String get_FullName() is a Method
. Da biste suzili pretragu upotrijebite FindMembers metodu koja uzima etiri parametra:
MemberFilter
Delegat (pogledajte poglavlje 12) koji filtrira popis lanova u Memberlnfo polju
objekata. Koristite filtar Type.FilterName koji je polje klase Type koje filtrira p0
imenu.
Object
Vrijednost znakovnog niza koju filtar koristi. U ovom sluaju prosljeujete Get*
da biste nali samo one metode koje poinju sa Get.
Kompletan popis dobiven filtriranjem ovih metoda je prikazan u primjeru 18-6.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
flendregion
namespace FindingParticularMembers
{
public class Tester
{
public static void Main()
{
// Ispituje jedan objekt
Type theType = Type.GetType(
"System.Reflection.Assembly" );
444 | Programiranje C#
P r im je r 18-6. Traenje odreenih lanova (nastavak)
Console.WriteLine( " { 0 } is a { i } 1',
mbrlnfo, mbrInfo.MemberType );
}
}
i
t Kasno povezivanje
H' Kad pronaete metodu mogue ju je pozvati koritenjem refleksije. Na primjer, moda
v budete htjeli pozvati Cos() metodu iz klase System.Math koja vraa kosinus kuta.
S tom informacijom o tipu moete dinamiki uitati instancu klase koristei statiku
metodu klase Activator. Poto je Cos() statika metoda ne trebate praviti instancu
System.Math klase (a i ne moete jer System.Math nema javni konstruktor).
Activator klasa sadri etiri metode (sve su statike) koje moete koristiti da napra-
vite objekte (lokalno ili udaljeno) ili da uzmete reference postojeih objekata. Te etiri
Vmetode su:
i CreateComlnstanceFrom
: Stvara instace COM objekta.
CreatelnstanceFrom
Stvara referencu na objekt iz odreenog sklopa i tipa imena.
; GetObject
Koristi se kod rasporeivanja objekata. Rasporeivanje (engl. marshaling) je
detaljno obraeno u poglavlju 19.
Createlnstance
Stvara lokalne ili udaljene instance objekta. Na primjer:
Object theObj = Activator.CreateInstance(someType);
Prije nego to moete pozvati metodu nad objektom morate uzeti metodu koju trebate
od objekta theMathType. Da biste to uinili pozvat ete GetMethod() proslijedivi '
potpis Cos metode.
Potpis metode, sjetit ete se, je ime metode (Cos) i njeni parametri tipa. Cos()imasamo
jedan parametar: realan broj (double). Meutim, Type.GetMethod uzima dva pararne
tra. Prvi je ime metode koju traite, a drugi su parametri. Ime se prosljeuje kao niz
znakova, a parametri kao polje tipova:
Methodlnfo Cosinelnfo =
theMathType.GetMethod(''Cos",paramTypes);
Ovaj kod deklarira polje Type objekata i zatim popunjava prvi element (paramTypes[oj)
s tipom koji predstavlja realan broj (double). Uzmite tip koji predstavlja double poziva-
njem statike metode Type.GetType() i prosljeivanjem niza System.Double.
Sad imate Methodlnfo objekt na kojem moete pozvati metodu. Da biste to uinili
morate proslijediti objekt nad kojim se metoda poziva i stvarnu vrijednost parametara
opet u polju. Postoje metoda statika, prosljedite objekt theMathType (da je Cos() bila
metoda instance, mogli biste upotrijebiti theObj umjesto theMathType).
Object[] parameters = new Object[l];
parameters[0] = 45 * (Math.PI/180); // 45 stupnjeva u radijanima
Object returnVal = Cosinelnfo.Invoke(theMathType,parameters);
a
Napravili ste dva polja. Prvo, paramTypes, sadri parametre tipa. Drugi,
parameters, sadri stvarnu vrijednost. Ako bi metoda uzela dva argu-
menta, trebali biste deklarirati ova polja da sadre dvije vrijednosti.
Ako metoda nije uzela nijednu vrijednost, opet moete napraviti polje,
ali mu veliinu postavite na nula!
Type[] paramTypes = new Type[0];
Ispravno je iako izgleda udno.
using System;
using System.Collections.Generic;
using System.Reflectlon;
using System.Text;
446 I Programiranje C#
( Primjer 18-7. Dinamiko pozivanje metode (nastavak)
Kendregion
| namespace DynamicallyInvokingAMethod
U
\ public class Tester
I {
i public static void Main()
\ (
) TyPe theMathType = Type.GetType( "System.Math" );
// Kako System.Math nema javni konstruktor
// izbacit e iznimku.
//Object theObj =
// Activator.CreateInstance(theMathType);
i)
Jl'Puno posls da bi se pozvala jedna metoda. Mo ovoga pristupa je u tome da moete
^upotrijebiti refleksiju kako biste nali sklop na korisnikovom raunalu, postavili upit
||o dostupnim metodama i dinamiki pozvali neku od tih metoda.
Dani integriranih programa koji rade u sklopu jednog procesa na jednom raunalu
su, ako ne mrtvi, onda barem ozbiljno ranjeni. Dananji programi se sastoje od sloe-
nih komponenata koje se izvode u vie procesa, esto preko mree. Web je omoguio
distribuirane aplikacije na nain koji je bio nezamisliv ak i prije nekoliko godina a
trend je prema distribuciji odgovornosti.
Proces je u biti aplikacija koja se izvodi. Ako objekt programa za obradu teksta eli
meudjelovati s objektom u proraunskoj tablici, oni moraju komunicirati preko gra-
nica procesa. Procesi su podijeljeni u aplikacijske domene. Aplikacijske domene (engl.
application domains) su dalje podijeljene u razne kontekste (engl. contexts ). Aplikacij-
ske domene djeluju kao jednostavni procesi, a konteksti stvaraju granice unutar kojih
se nalaze objekti sa slinim pravilima. Objekti e povremeno biti rasporeivani preko
granica konteksta i aplikacijskih domena kao i preko granica procesa i raunala.
Kad se objekt rasporeuje po vrijednosti to izgleda kao da ga se alje kroz icu od jed-
nog raunala prema drugom, kao to se kapetan Kirk teleportira na povrinu planeta
nekoliko stotina kilometara ispod orbitirajueg USS Enterprisea.
448
U Z vjezdanim s ta z am a , Kirk je zaista premjeten na planet, ali u .NET-u to je iluzija.
Ako stojite na povrini planeta, mogli biste misliti da vidite pravog Kirka i razgovarate
s njim, ali uope ne razgovarate s Kirkom ve s posrednikom, moda hologramom, iji
je posao da prenese vau poruku do Enterprisea, pravom Kirku.
Izmeu vas i Kirka postoji vei broj odvoda". Odvod (engl. sink) je objekt iji je posao
da provodi pravila. Na primjer, ako vam Kirk pokua rei neto to bi moglo utjecati
na razvoj vae civilizacije, odvod primarne direktive bi mogao zabraniti prijenos.
' Kad pravi Kirk odgovori, on alje odgovor kroz razne odvode dok poruka ne doe do
posrednika i posrednik vam ne prenese poruku. Vama se ini kao da je Kirk zapravo
tamo, ali on se zapravo prikrada iza vas da osujeti va podli plan. Naalost, ispada da
je gospodin Sulu cijelo vrijeme kontrolirao hologram. Vie sree u sljedeoj epizodi.
, Stvarni prijenos vae poruke obavlja kanal (engl. channel). Posao kanala je da zna
kako prenijeti poruku od Enterprisea do planeta. Kanal radi s formaterom (engl. for-
matter). Formater osigurava da je poruka u odgovarajuem formatu. Moda govorite
samo vulkanski, a jadni kapetan ne. Formater moe prevesti poruku na standardni
federacijski jezik i prevesti Kirkov odgovor sa standardnog federacijskogjezika natrag
na vulkanski. ini se da razgovarate jedan s drugim, ali formater (poznat kao univer-
\ zalni prevoditelj u Zvjezdanim stazama) neprimjetno omoguava komunikaciju.
, Ovo poglavlje opisuje kako se objekti mogu prenositi preko raznih granica i kako
\ posrednici i zamjenski elementi mogu stvoriti iluziju da je va objekt prenesen kroz mre-
ni kabel do raunala na drugom kraju ureda ili svijeta. Pored toga, ovo poglavlje opi-
suje uloge formatera, kanala i odvoda te primjenu ovih koncepata u programiranju.
Aplikacijske domene
Proces je u biti aplikacija koja se izvodi. Svaka .NET aplikacija se izvodi unutar vla-
stitog, procesa. Ako imate otvorene programe Word, Excel i Visual Studio, imate tri
procesa koji se izvode. Ako otvorite Outlook, pokree se novi proces. Svaki proces
Wi je podijeljen na jednu ili vie aplikacijskih domena. Aplikacijska domena djeluje kao
proces, ali koristi manje resursa.
Aplikacijske domene mogu se neovisno pokretati i zaustavljati. One su sigurne, jed-
nostavne i svestrane. Aplikacijska domena moe pruiti otpornost na pogreke. Ako
W pokrenete objekt u drugoj aplikacijskoj domeni i onda se izvoenje prekine, to e sru-
iti aplikacijsku domenu, ali ne i cijeli program. Moete zamisliti Web posluitelj koji
koristi aplikacijsku domenu za izvoenje korisnikovog koda. Ako u kodu ima neki
problem, Web posluitelj moe nastaviti raditi.
Aplikacijsku domenu uahurava instanca klase AppDomain, koja prua vei broj metoda
i svojstava. U tablici 19-1 je skraeni popis.
CurrentDomain Javno statiko svojstvo koje vraa aplikacijsku dom enu za trenutnu dretvu
CreateDomain() Preoptereena javna statika m etoda koja stvara novu aplikacijsku dom enu
Unload() Javna statika m etoda koja brie zadanu aplikacijsku dom enu
FriendlyName Javna svojstvo koje vraa lako prijateljsko im e za aplikacijsku dom enu
DefineDynamicAssembly() Preoptereena javna statika m etod a koja definira dinam iki sklop u trenutnoj
aplikacijskoj dom eni
GetData() Javna m etoda koja uzim a vrijed nost sprem ljenu u tren u tn o j aplikacijskoj domeni
Load() Javna m etoda koja uitava sklop u trenutnu aplikacijsku dom enu
SetAppDomainPolicy() Javna m etoda koja postavlja sigurnosna pravila za trenu tn u aplikacijsku domenu
SetData() Javna m etoda koja stavlja podatke u zadano svojstvo aplikacijske dom ene
4S0 | Programiranje C#
koriste da izoliraju aplikacije. Unutar aplikacijske domene u nekom trenutku moe biti
vie dretvi koje se izvode (pogledajte poglavlje 22).
Da biste vidjeli kako rade aplikacijske domene, postavimo sljedei primjer. Pretposta-
vimo da elite da program instancira klasu Shape, ali u drugoj aplikacijskoj domeni.
a*
Nema pravog razloga za smjetanje klase Shape u drugu aplikacijsku
domenu, osim da se prikae kako ovaj koncept funkcionira. Mogue je,
meutim, da sloenijim objektima zatreba druga aplikacijska domena
kako bi se osigurao drugi sigurnosni okoli. Nadalje, ako stvarate klase
koje bi mogle sudjelovati u riskantnom ponaanju, moda biste se htjeli
zatititi tako da ih pokrenete u drugoj aplikacijskoj domeni.
Normalno, uitali biste Shape klasu iz sklopa, ali da primjer ostane jednostavan, stavit
ete definiciju klase Shape u istu datoteku u kojoj se nalazi i sav drugi izvorni kod u ovom
primjeru (pogledajte poglavlje 17). Nadalje, u proizvodnom okoliu mogli biste pokre-
nuti metode Shape klase u odvojenoj dretvi, ali radi jednostavnosti ete zasad zanemariti
dretve (dretve su detaljno obraene u poglavlju 20). Izbjegavanjem ovih pitanja, moete
primjer sauvati jednostavnim i koncentrirati se na detalje stvaranja i koritenja aplika-
cijskih domena i premjetanja objekata preko granica aplikacijskih domena.
Time se stvara nova aplikacijska domena s prijateljskim imenom Shape Domain. Prijatelj-
sko ime (engl. friendly name) je pogodnost za programera. To je nain za programski
rad s domenom, bez znanja o internom prikazu domene. Moete provjeriti prijateljsko
ime domene u kojoj radite tako da provjerite svojstvo System.AppDomain.CurrentDo-
main.FriendlyName.
Kad ste instancirali AppDomain objekt, moete napraviti instance klasa, suelja itd.
koritenjem metode Createlnstance(). Evo njenog potpisa:
public ObjectHandle Createlnstance(
string assemblyName,
string typeName,
bool ignoreCase,
BindingFlags bindingAttr,
Binder binder,
object[] args,
Culturelnfo culture,
objectf] activationAttributes,
Evidence securityAttributes
);
i naina upotrebe:
Prvi parametar (ProgCSharp) je ime sklopa, a drugi parametar (ProgCSarp. Shape) je ime
klase. Ime klase mora biti potpuno kvalificirano.
Spona (engl. binder) je objekt koji omoguava dinamiko povezivanje sklopa prilikom
izvoenja. Njen posao je da vam omogui prosljeivanje informacija o objektu koji
elite napraviti, da napravi taj objekt za vas i da povee referencu na taj objekt. U veli-
koj veini sluajeva, ukljuujui ovaj primjer, koristit ete podrazumijevanu sponu
to se postie prosljeivanjem nuli.
Zastavice za povezivanje pomau sponi da fino prilagodi svoj nain rada prilikom
povezivanja. U ovom primjeru, upotrijebite vrijednost Createlnstance enumeracije Bin-
dingFlags. Podrazumijevana spona obino povezuje samo javne klase, ali moete dodati
zastavice tako da spona povezuje i javne klase ako imate odgovarajua doputenja.
Kad povezujete sklop prilikom izvoenja nemojte ga postaviti tako da se uita u vri-
jeme prevoenja. Radije programski zadajte koji sklop elite i s njim poveite varijablu
prilikom izvoenja programa.
Konstruktor kojeg pozivate uzima dvije cjelobrojne vrijednosti koje moraju biti sta-
vljene u polje objekata (new ob jec tf] {3 ,5 })- Moete poslati nuli vrijednost za kulturu
jer ete koristiti podrazumijevanu (en) kulturu i neete specificirati aktivacijske ili
sigurnosne atribute.
Dobivate natrag identifikator objekta (engl. ob jed handle) - tip koji se koristi za proslje-
ivanje objekta (u omotanom stanju) izmeu vie aplikacijskih domena bez uitavanja
metapodataka omotanog objekta u svakom objektu kroz kojeg identifikator ObjectHan-
dle prolazi. Stvarni objekt moete dobiti pozivanjem Unwrap() metode na identifikatoru
objekta i pretvaranjem rezultirajueg objekta u stvarni tip, u ovom sluaju Shape.
452 | Programiranje C#
Createlnstance() metoda prua mogunost da napravite objekt u novoj aplikacijskoj
domeni. Ako biste napravili objekt koritenjem new operatora, bio bi napravljen u tre-
nutnoj aplikacijskoj domeni.
Kad je objekt serijaliziran, njegovo interno stanje se ispisuje u tok, bilo za rasporeiva-
nje ili za spremanje. Detalji serijalizacije su obraeni u poglavlju 21.
Najlaki nain da uinite da se objekt rasporeuje po referenci jest da izvedete njegovu
klasu iz MarshalByRefObject:
public class Shape : MarshalByRefObject
Klasa Shape imat e samo jednu varijablu lanicu -u p p erleft. Ta varijabla e biti Point
objekt koji sadri koordinate gornjeg lijevog kuta oblika.
Konstruktor za Shape e inicijalizirati svog Point lana:
public Shape(int upperLeftX, int upperLeftY)
{
Console.WriteLine( ''[{0}] Eventfl}",
System.AppDomain.CurrentDomain.FriendlyName,
"Shape constructor");
upperLeft = new Point(upperLeftX, upperLeftY);
}
Opskrbite Shape metodom za prikazivanje pozicije:
public void ShowUpperLeft()
{
Console.WriteLine( "[{o}] Upper left: {l},{2}",
System.AppDomain.CurrentDomain.FriendlyName,
upperLeft.X, upperLeft.Y);
}
454 | Programiranje C#
Takoer pruite i drugu metodu za vraanje njegove upperLeft varijable:
public Point GetUpperLeft()
{
return upperLeft;
}
point klasa je takoer vrlo jednostavna. Sadri konstruktor koji inicijalizira svoje dvije
varijable lanice i metode za uzimanje njihovih vrijednosti.
Kad uzmete Shape zatraite njegove koordinate:
sl.ShowllpperLeft(); // Trai od objekta da se prikae
Zatim zatraite da vrati svoju upperLeft koordinatu kao Point objekt koji ete
promijeniti:
Point localPoint = sl.GettlpperLeft();
localPoint.X = 500;
localPoint.V = 600;
using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Reflection;
using System.Text;
Sendregion
namespace Marshaling
{
this.x = x;
this.y = y;
public int X
{
get
{
Console.WriteLine( "[{0}] {l}",
System.AppDomain.CurrentDoinain.FriendlyName)
"Point x.get");
return this.x;
}
set
{
Console.WriteLine( "[{0}] {l}",
System.AppDomain.CurrentDomain.FriendlyName,
"Point x.set");
this.x = value;
}
public int V
{
get
{
Console.WriteLine( "[{0}] {l}",
System.AppDomain.CurrentDomain.FriendlyName,
"Point y.get");
return this.y;
}
set
{
Console.WriteLine( "[{0}] {l}",
System.AppDomain.CurrentDomain.FriendlyName,
"Point y.set");
this.y = value;
}
}
}
// Klasa shape rasporeuje po referenci
public class Shape : MarshalByRefObject
{
456 | Programiranje C#
primjer 19-1. Rasporeivanje preko granica aplikacijske domene (nastavak)
private Point upperLeft;
// Assembly a = Assembly.LoadFromCProgCSharp.exe");
// Object theShape = a.CreateInstance("Shape);
// Instanciranje Shape objekta
ObjectHandle oh = ad2.CreateInstance(
"Marshaling",
"Marshaling.Shape", false,
System.Reflection.BindingFlags.CreateInstance,
nuli, new objeetj] {3, 5},
nuli, nuli, nuli );
Ovaj put dobijate posrednika za Point objekt i svojstva se postavljaju preko posrednika
na originalnu Point varijablu lanicu. Prema tome, promjene se odraavaju unutar
samog Shape.
Kontekst
Aplikacijske domene su podijeljene na kontekste. Kontekst (engl. context) se moe
shvatiti kao podruje unutar kojeg objekti dijele pravila koritenja. Ta pravila uklju-
uju sinkronizacijske transakcije (pogledajte poglavlje 20), i tako dalje.
458 | Programiranje C#
Kontekstno vezani i okretni objekti
Objekti mogu biti vezani za kontekst (engl. context-bound ) ili okretni (engl. agile).
su kontekstno vezani oni postoje u nekom kontekstu i da bi se s njima komuni-
55
ciralo, poruka mora biti rasporeena. Ako su okretni, objekti djeluju unutar kontek-
sta objekta koji ih je pozvao: njihove metode se izvode u kontekstu objekta koji ih je
pozvao pa rasporeivanje nije potrebno.
394- Pretpostavite da imate objekt A koji meudjeluje s bazom podataka pa je oznaen da
podrava transakcije. To ini kontekst. Svi pozivi metoda na objektu A se dogaaju
unutar konteksta zatite koji prua transakcija. Objekt A moe odluiti da poniti
transakciju, a sve akcije poduzete nakon zadnjeg odobrenja su ponitene.
Pretpostavite da imate drugi objekt, B, koji je okretan. Sad pretpostavite da objekt pro-
'?p sljeduje referencu baze podataka objektu B i zatim poziva metodu na B. Moda su A i B
T upovratnoj vezi, u kojoj e objekt B obaviti neki posao i zatim vratiti rezultate objektu A.
Kako je B okretan objekt, njegove metode djeluju u kontekstu objekta koji ih je pozvao.
Prema tome, bit e mu dodijeljena zatita koju prua objekt A. Promjene koje B napravi
u bazi podataka bit e ponitene ako A poniti transakciju jer se metode objekta B izvode
unutar konteksta objekta koji ih je pozvao. Do sada sve funkcionira kako treba.
i Da li bi objekt B trebao biti kontekstno vezan ili okretan? U razmotrenom sluaju B
je dobro funkcionirao kao kontekstno vezan. Pretpostavite da postoji jo jedna klasa,
t klasa C. Ona ne posjeduje transakcije i poziva metodu na objektu B koja mijenja bazu
podataka. Sad objekt A pokuava ponititi transakciju, ali na nesreu, posao koji je
B obavio za C se odvio u kontekstu klase C i zato nije imao podrku za transakcije.
Huh, taj posao ne moe biti poniten.
Da je B bio kontekstno vezan objekt kad ga je A napravio, onda bi B naslijedio kon-
s tekst objekta A. U tom sluaju, kada je C pozvala metodu na objektu B, ona bi trebala
t. biti rasporeena preko granice konteksta, ali kad bi B izveo metodu, onda bi to bilo u
kontekstu transakcije objekta A. Ovo je ve puno bolje.
' To bi funkcioniralo ako bi B bio kontekstno vezan, ali bez atributa. B bi naravno
... mogao imati atribute iz vlastitog konteksta, a ti bi atributi mogli nametnuti objektu B
da bude u razliitom kontekstu od objekta A. Na primjer, objekt B bi mogao imati tran-
si sakcijski atribut RequiresNew. U tom sluaju, objekt B bi u trenutku stvaranja dobio
, novi kontekst i zato ne bi mogao biti u kontekstu objekta A. Prema tome, kad bi objekt
A ponitio transakciju, posao koji je obavio objekt B ne bi mogao biti poniten. Mogli
biste oznaiti objekt B s vrijednou enumeracije RequiresNewjer je objekt B kontrolna
metoda. Kad objekt A poduzme akciju nad bazom podataka, on obavjetava objekt B
koji aurira kontrolu unosa. Ne elite da posao koji je obavio objekt B bude poniten
kad objekt A poniti svoju transakciju. elite da objekt B bude u vlastitom transakcij-
skom kontekstu, ponitavajui samo vlastite pogreke, a ne i one od objekta A.
{ Objekt prema tome ima tri izbora. Prvi izbor je da bude okretan. Takvi objekti djeluju
Si u kontekstu pozivatelja. Drugi izbor je da bude vezan za kontekst (to se postie izvo-
l i enjem iz ContextBoundObject, ali bez vlastitih atributa kako bi djelovao u kontekstu
ifc
to ete odabrati ovisi o tome kako e se objekt koristiti. Ako je objekt jednostavan
kalkulator koji moda zahtijeva sinkronizaciju ili transakcije ili podrku za kontekst,
onda bi ga trebali napraviti da bude okretan. Ako bi va objekt trebao koristiti kon-
tekst objekta koji ga stvara, trebali biste ga napraviti tako da bude vezan za kontekst
pozivatelja, ali bez atributa. Konano, ako va objekt ima svoje zahtjeve u vezi s kon-
tekstom, trebali biste mu dodijeliti odgovarajue atribute.
Objekti se, ovisno o tome kako su stvoreni, drugaije rasporeuju preko granica kon-
teksta:
Tipini objekti se uope ne rasporeuju. Okretni su unutar aplikacijskih
domena.
Objekti oznaeni atributom Serializable rasporeuju se po vrijednosti preko apli-
kacijskih domena i okretni su.
Objekti koji izvode iz MarshalByRefObject rasporeuju se po referenci preko apli-
kacijskih domena i okretni su.
Objekti koji izvode iz ContextBoundObject rasporeuju se po referenci preko apli-
kacijskih domena i preko granica konteksta.
Rad na daljinu
Osim to se mogu rasporeivati preko granica konteksta i aplikacijskih domena,
objekti se mogu rasporeivati i preko granica procesa pa ak i preko granica raunala.
460 | Programiranje C#
Kad je objekt rasporeen, bilo po vrijednosti ili po posredniku, preko granice izmeu
procesa ili raunala, onda se kae da se s njim radi na daljinu.
fI
Razumijevanje tipova posluiteljskih objekata
U .N ET kosturu postoje dva tipa posluiteljskih objekata s kojima se moe raditi na
daljinu: dobro poznati i klijentski aktivirani. Komunikacija sa dobro poznatim objek-
tima (engl. well known objects) se uspostavlja svaki put kad klijent poalje poruku. Za
razliku od klijentski aktiviranih objekata, ne postoji stalna veza sa dobro poznatim
objektima.
Dobro poznati objekti dolaze u dvije varijante: kao unikatni (engl. singleton) i s jed-
nim pozivom (engl. single call). Kod dobro poznatih unikatnih objekata sve poruke za
objekt, od svih klijenata, otpremaju se jednom objektu koji se izvodi na posluitelju.
On se stvara kad se klijent prvi put pokua spojiti s njim i postoji da bi pruio uslugu
bilo kojem klijentu koji mu moe pristupiti. Dobro poznati objekti moraju imati kon-
struktor bez parametara.
Ako se koristi dobro poznati objekt s jednim pozivom, svaku novu poruku od kli-
jenta obrauje novi objekt. To je vrlo korisno kod skupina posluitelja, gdje se nizovi
poruka od klijenta mogu naizmjence obraivati na razliitim posluiteljima ovisno o
optereenju.
using System;
using System.Collections.Generic;
using System.Text;
#endregion
s? Klijentski aktivirani objekti mogu biti manje robustni. Ako poziv klijentski aktiviranog objekta ne uspije,
projektant mora pretpostaviti da se objekt izgubio na posluitelju i mora ga ponovno stvoriti.
f
Izgradnja posluitelja
Da biste napravili posluitelj koji je koriten u primjeru 19-3, napravite CalculatorSer-
ver.es u novom C # Console Application projektu (obavezno ukljuite referencu prema
Calculator.dll) i prevedite ga odabirom opcije Build s izbornika.
CalculatorServer klasa implementira ICalc. Ona izvodi iz MarshalByRefObject pa e
dostaviti posrednika kalkulatora klijentskoj aplikaciji:
class CalculatorServer : MarshalByRefObject, Calculator.ICalc
Ovaj korak informira .NET da ete pruati HTTP usluge na portu 65100, slino kao
to US radi na portu 80. Poto ste registrirali HTTP kanal, a niste osigurali formater,
pozivi metoda e koristiti SOAP formater kao podrazumijevani.
Sad ste spremni od klase RemotingConfiguration zahtijevati da registrira vae dobro
poznate objekte. Morate proslijediti tip objekta kojeg elite registrirati, zajedno sa
zavrnom tokom (engl. endpoint). Zavrna toka je ime koje e RemotingConfiguration
povezati s vaim tipom. Ona kompletira adresu. Ako IP adresa identificira raunalo,
a ulaz identificira kanal, onda zavrna toka pokazuje tonu uslugu. Da biste uzeli tip
objekta, moete koristiti typeof koji vraa Type objekt. Proslijedite puno ime objekta
iji tip elite:
Type calcType =
typeof( "CalculatorServerNS.CalculatorServer" );
using System;
using System.Collections.Generic;
using $ystem.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Text;
tfendregion
namespace CalculatorServerNS
{
class CalculatorServer : MarshalByRefObject, Calculator.ICalc
{
public CalculatorServerf)
{
Console.WriteLine( "CalculatorServer constructor" );
}
// Implementira etiri metode
public double Add( double x, double y )
{
Console.WriteLine( "Add {0} + {!}", x, y );
Type calcType =
Type.GetType( "CalculatorServerNS.CalculatorServer" );
464 | Programiranje C#
Izgradnja klijenta
Dok e CLR unaprijed registrirati TCP i HTTP kanal, vi ete trebati registrirati kanal
na klijentu ako elite primati povratne pozive ili ako koristite nestandardni kanal. U
ovom primjeru, moete koristiti kanal 0:
HTTPChannel chan = new HTTPChannel(O);
ChannelServices.RegisterChannel(chan);
Klijent se sada samo treba spojiti na daljinu prosljeujui objekt Type koji predstavlja
tip objekta kojeg treba (u naem sluaju ICalc suelje) i Uniform Resource Identifier
(URI) usluge.
Object obj =
RemotingServices.Connect
(typeof(Programming_CSharp.ICalc),
"http://localhost:65lOO/theEndPoint");
Usluga bi trebala vratiti objekt koji je suelje koje ste traili. Onda ga moete pretvoriti
u suelje i poeti ga koristiti. Poto rad na daljinu ne moe biti zajamen (mrea moe
s' biti iskljuena, posluitelj moe biti nedostupan, itd.), trebali biste upotrebu staviti u
try blok:
try
{
Programming_CSharp.ICalc calc =
obj as Programming_CSharp.ICalc;
l
double sum = calc.Add(3,4);
Sad imate posrednik za kalkulator koji se izvodi na posluitelju, ali koji se moe koris-
titi i na klijentu, preko granica procesa ili, ako vam se vie svia, preko granica izmeu
raunala. Primjer 19-4 prikazuje kompletan klijent (da biste ga mogli prevesti morate
ukljuiti referencu na Calculator.dll kao to ste to uinili s CalcServer.cs).
using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Text;
:U.
#endregion
f namespace CalculatorClient
f f
try
{
// Pretvara objekt u suelje
Calculator.ICalc calc = obj as Calculator.ICalc;
// Ispisuje rezultate
Console.WriteLine(3+4 = {0}", sum);
Console.WriteLine("3-4 = {0}", difference);
Console.WriteLine("3*4 = {0 }", product);
Console.WriteLine(3/4 = {0}", quotient);
}
catch( System.Exception ex )
{
Console.Writeline("Exception caught: ");
Console.WriteLine(ex.Message);
}
}
}
}
Nakon pokretanja posluitelj eka da korisnik pritisne Enter i tako mu javi da moe
prestati s radom. Klijent se pokree i prikazuje poruku na konzoli. Klijent zatim poziva
svaku od etiri operacije. Vidite da posluitelj ispisuje poruke nakon poziva metoda,
a zatim se rezultati ispisuju na klijentu.
To je tako jednostavno. Sad imate kod koji se izvodi na posluitelju i prua usluge
klijentu.
466 | Programiranje C#
Upotreba SingleCall
Da biste vidjeli razlika izmeu SingleCall i Singleton objekata promijenite jedan red
u posluiteljskoj Main() metodi. Evo postojeeg koda:
RemotingConfiguration.RegisterWellKnownServiceType
( calcType,
"theEndPoint",
WellKnownObjectMode.Singleton );
RemotingConfiguration.RegisterWellKnownServiceType
( calcType,
"theEndPoint,
WellKnownObjectMode. SingleCall);
Da biste to sami uinili trebali biste modificirati primjer 19-3 tako da Main() instan-
cira Calculator i onda ju proslijedi Marshal() metodi iz RemotingServices sa zavrnom
tokom kojoj elite pridruiti tu instancu Calculator. Modificirana metoda Main()
je prikazana u primjeru 19-5 i, kao to moete vidjeti, izlaz je identian onome iz
primjera 19-3.
CalculatorServerNS.CalculatorServer calculator =
Sad moete pozvati metode na posluitelju koristei ICalc koje djeluje kao posrednik
za objekt Calculator koji se izvodi na posluitelju i kojeg ste opisali u calculatorSoap.
txt datoteci. Kompletna zamjena za klijentsku Main() metodu je prikazana u primjeru
19-6. Ovom primjeru trebate dodati dvije using deklaracije.
U ...
FileStream fileStream =
468 | Programiranje C#
Primjer 19-6. Zamjena za Main() metodu iz primjera 19-4 (klijent) (nastavak)
new FileStream ("calculatorSoap.txt", FileMode.Open);
SoapFormatter SoapFormatter =
rew SoapFormatter ();
try
{
ICalc calc=
(ICalc) SoapFormatter.Deserialize (fileStream);
// Ispisuje rezultate
Console.WriteLine("3+4 = {0}", sum);
Con$ole.WriteLine("3-4 = {0 }", difference);
Console.WriteLine("3*4 = {0 }", product);
Console.WriteLine("3/4 = {0 }", quotient);
}
catch( System.Exception ex )
1
Con5ole.WriteLine(Exception caught: ");
Console.WriteLine(ex.Message);
}
}
Kad se klijent pokrene, datoteka se uitava sa diska i posrednik se opoziva. Ovo je
inverzna operacija rasporeivanja i serijaliziranja objekta na posluitelju. Kad ste to
obavili, moete pozivati metode na objektu Calculator koji se izvodi na posluitelju.
FileStream fileStream =
new FileStream("calculatorSoap.txt",FileMode.Create);
soapFormatter.Serialize(fileStream,objRef);
fileStream.Close();
470 | Programiranje C#
POGLAVLJE 20
Dretve i sinkronizacija
471
Dretve
Dretve se tipino stvaraju kad elite da program radi dvije stvari odjednom. Na pri-
mjer, pretpostavimo da elite izraunati pi (3.141592653589...) na milijarditu deci-
malu. Procesor e veselo poeti raunati, ali nita se nee ispisivati na zaslonu. Poto
e to raunanje potrajati nekoliko tjedana, moda biste htjeli da procesor prui infor-
macije o napretku dok radi. U dodatku, moda bi htjeli osigurati gumb Stop tako da
korisnik moe zaustaviti raunanje u bilo kojem trenutku. Da bi dozvolili programu
da obrauje pritisak na gumb Stop trebat ete drugu dretvu izvoenja.
Jo jedna situacija kad ete esto koristiti dretve je kad morate ekati neki dogaaj kao
to je korisniki ulaz, itanje iz datoteke ili primanje podataka preko mree. Dozvolja-
vanje procesoru da obrati pozornost na drugi zadatak dok ekate (kao to je raunanje
jo 10000 vrijednosti broja pi) je dobra ideja i omoguava programu da radi jo bre.
U nekim situacijama dretve mogu usporiti program. Pretpostavite da osim izraunava-
nja broja pi elite odrediti Fibonaccijev niz (1 ,1 ,2,3,5,8,13,21...). Ako imate vieproce-
sorski sustav raunanje e se izvoditi bre ako svaki procesor rauna u posebnoj dretvi.
Ako imate jednoprocesorski sustav, (kao to veina korisnika ima), raunanje ovih vri-
jednosti u vie dretvi e se izvoditi sporije nego raunanje jedne pa onda druge u istoj
dretvi jer se procesor mora prebacivati izmeu dretvi. To dodatno optereuje sustav.
Pokretanje dretvi
Najjednostavniji nain da napravite dretvu je da napravite novu instancu klase Thread.
Thread konstruktor uzima jedan argument: delegate instancu. CLR prua klasu dele-
gata ThreadStart posebno za ovu svrhu. Ona upuuje na metodu koju zadate. To omo-
guava da se napravi dretva i da joj se kae: Kad se pokrene, izvedi ovu metodu".
Deklaracija ThreadStart delegata je:
public delegate void ThreadStart();
Kao to moete vidjeti, metoda koju pridruite ovom delegatu ne smije uzimati parame-
tre i mora vraati void. Prema tome, moete napraviti novu dretvu na sljedei nain:
Thread myThread = new Thread( new ThreadStart(myFunc) );
Na primjer, moete napraviti dvije radne dretve, jednu koja broji od nule:
public void Incrementer()
{
for (int i =0;i<1000;i++)
{
Console.WriteLine('Tncrementer: {0}", i);
}
}
i jednu koja broji prema od 1000 prema nuli:
public void Decrementer()
{
for (int i = 1000;i>=0;i--)
472 | Programiranje C#
{
Console.WriteLine("Decrementer: {0}", i);
}
}
Da biste ove metode izvodili u dretvama napravite nove dretve i inicijalizirajte ih s
ThreadStart delegatom. One e biti inicijalizirane odgovarajuim metodama'.
Thread t i = new Thread( new ThreadStart(Incrementer) );
Thread t2 = new Thread( new ThreadStart(Decrementer) );
Primjer 20-1 prikazuje cijeli program i njegov izlaz. Trebat ete dodati using deklara-
ciju za System.Threading da prevoditelj uzme u obzir klasu Thread. Obratite panju na
izlaz gdje moete vidjeti kako se procesor prebacuje izmeu ti i t2.
using System;
using System.Collections.Ceneric;
using System.Text;
using System.Threading;
(tendregion
namespace UsingThreads
{
class Tester
{
static void Main()
{
// Pravi instancu klase
Tester t = new Tester();
Console.WriteLine( "Hello" );
// Izvodi se izvan statike Main
t.DoTestO;
}
// Pokree dretve
tl.Start();
t2.Start();
474 | Programiranje C#
Procesor dozvoljava prvoj dretvi da se izvodi sve dok ne doe do 106. Onda se ubacuje
druga dretva, brojei neko vrijeme unatrag od 1000. Zatim je opet prvoj dretvi dozvoljeno
da se izvodi. Kad ovaj primjer pokrenem za vee brojeve, primjeeujem da je svakoj dretvi
dozvoljeno da odbroji 100 brojeva prije nego to se izvedba prebaci na drugu dretvu.
Spajanje dretvi
Kad kaete dretvi da prestane s izvoenjem i prieka dok druga dretva ne zavri posao
tada ste spojili prvu dretvu s drugom. To je kao da ste povezali vrh prve dretve na rep
druge dretve, dakle spojili ih.
Da bi povezali dretvu 1 (ti) s dretvom 2 (t2), napiite:
t2.3oi.nO;
Ako se ova deklaracija izvede u metodi u dretvi ti, onda e ti stati i ekati dok se t2
ne zavri. Na primjer, mogli biste od dretve u kojoj se izvodi Main() zatraiti da saeka
sve ostale dretve da se zavre prije nego to ispie svoju zakljunu poruku. U sljedeem
odlomku koda pretpostavit emo da ste napravili kolekciju dretvi myThreads. Proite
kroz kolekciju spajajui trenutnu dretvu sa sljedeom dretvom iz kolekcije:
foreach (Thread myThread in myThreads)
{
myThread.3oin();
}
Poruka Ali my threads are done nee biti ispisana dok sve dretve ne zavre. U stvarnoj
situaciji mogli biste pokrenuti niz dretvi za obavljanje zadataka (na primjer, za ispis,
auriranje prikaza itd.) i ne nastavljati glavnu dretvu dok sve radne dretve ne zavre.
Iako timeSpan objekti mogu mjeriti trenutke (100 nanosekundi), zrnatost Sleep()
metode je u milisekundama (1000000 nanosekundi).
Povremeno ete kao period odgaanja dretve navesti nulu. To programu za rasporeiva-
nje dretvi govori da biste htjeli da dretvu prepusti drugoj dretvi da se izvodi, ak i ako
bi program za rasporeivanje dretvi prvoj dretvi dao jo malo vremena za izvoenje.
Ako prom ijenite prim jer 20 -1 dodavanjem Thread. S le e p (i) iskaza nakon svake Write-
L in e(), izlaz e se znatno prom ijeniti:
for (int i =0 ;i<1 0 0 0 ;i++)
{
Console.WriteLine(
"Incrementer: {o}", i);
Thread.Sleep(l);
}
Ova mala promjena je dovoljna da svakoj dretvi da priliku da se izvodi dok druga
dretva ispisuje vrijednost. Izlaz odraava ovu promjenu:
Incrementer: 0
Incrementer: l
Decrementer: 1000
Incrementer: 2
Decrementer: 999
Incrementer: 3
Decrementer: 998
Incrementer: 4
Decrementer: 997
Incrementer: 5
Decrementer: 996
Incrementer: 6
Decrementer: 995
Prekidanje dretvi
Dretve se obino prekidaju nakon to obave posao. Meutim, moete narediti dretvi
da se prekine. Najbolji nain za to je da postavite KeepAlive Boolean zastavicu koju
dretvu moe povremeno provjeriti. Kad zastavica promijeni stanje (na primjer, sa true
na false) dretva se moe sama zaustaviti.
Alternativni nain je da pozovete T h r e a d . I n t e r r u p t za prekidanje izvoenja dretvi.
Konano, u oaju i ako zaustavljate aplikaciju moete pozvati Trhea d. Abor t. To e
izbaciti iznimku Thread AbortEx ception, koju dretva moe uhvatiti.
Dretva bi iznimku Thr eadA bortException trebala promatrati kao signal da isti tren
prekine s radom.
Moda biste htjeli prekinuti dretvu odgovarajui na neki dogaaj, kao kad korisnik
pritisne Cancel gumb. Metoda za obradu dogaaja za gumb Cancel bi mogla biti u
dretvi t i , a dogaaj koji se zaustavlja bi mogao biti u dretvi t2 . U metodi za obradu
dogaaja moete pozvati Abort na t i :
476 | Programiranje C#
tl. A b ort();
U primjeru 20-2, stvorene su tri dretve i spremljene u polje Thread objekata. Prije
pokretanja dretve svojstvo IsBackground je postavljeno na true (pozadinske dretve su
potpuno jednake kao glavne dretve, osim to one ne prekidaju proces). Svaka dretva je
pokrenuta i imenovana (na primjer, Threadi, Thread2 i tako dalje). Prikazuje se poruka
koja govori da je dretva pokrenuta i onda se glavna dretva odgaa za 50 milisekundi
prije nego to se pokrene sljedea dretva.
Nakon to su sve tri dretve pokrenute i prolo je sljedeih 50 mlisekuni, prva dretva
se prekida pozivanjem Abort() metode. Glavna dretva se onda povezuje sa sve tri
dretve koje se izvode. Uinak toga je da se glavna dretva nee nastaviti dok sve ostale
dretve ne budu dovrene. Kad dretve zavre, glavna dretva ispisuje poruku: Ali my
threads are done. Kompletan izvorni kod je prikazan u primjeru 20-2.
using System;
using System.Collections.Generic;
using System.Text;
using System,Threading;
#endregion
namespace InterruptingThreads
{
class Tester
{
static void Main()
' {
// Stvara instancu ove klase
Tester t = new Tester();
478 | Programiranje C#
Primjer 20-2. Prekidanje dretve (nastavak)
finally
{
Console.WriteLine(
"Thread {0} Exiting. ",
Thread.CurrentThread.Name);
}
}
480 | Programiranje C#
prolazu dogaa se isto. Umjesto da imate dvije dretve koje broje 1 ,2 ,3 , 4, vidjet ete 1,
2 , 3 , 3 , 4, 4. Primjer 20-3 prikazuje kompletan izvorni kod i izlaz za ovaj primjer.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
Sendregion
namespace SharedResource
{
class Tester
{
private int counter = 0 ;
// Pokusna metoda, b ro ji do lK
public void Incrementer()
{
try
{
while ( counter < 1000 )
{
int temp = counter;
temp++; // Poveavanje
Izlaz:
Started thread ThreadOne
Started thread ThreadTwo
Thread ThreadOne. Incrementer: 1
Thread ThreadOne. Incrementer: 2
Thread ThreadOne. Incrementer: 3
Thread ThreadTwo. Incrementer: 3
Thread ThreadTwo. Incrementer: 4
Thread ThreadOne. Incrementer: 4
Thread ThreadTwo. Incrementer: 5
Thread ThreadOne. Incrementer: 5
Thread ThreadTwo. Incrementer: 6
Thread ThreadOne. Incrementer: 6
482 | Programiranje C#
Poveavanje i smanjivanje vrijednosti zajedanje tako uobiajen programerski model i
esto treba sinkronizajsku zatitu. Zbog toga CLR prua posebnu klasu Interlocked
samo za ovu svrhu. Interlocked ima dvije metode Increment i Decrement koji ne samo
da poveavaju i umanjuju vrijednost, ve to rade uz kontroliranu sinkronizaciju.
Promijenite Incrementer metodu iz primjera 20-3 na sljedei nain:
public void Incrementer()
{
try
{
while (counter < 1000)
{
int ter'ip = Interlocked.Increment(ref counter);
Kad je ova promjena uinjena pristup counter varijabli je sinkroniziran i izlaz je kao
to oekujete.
Izlaz (odlomak):
Started thread ThreadOne
Started thread ThreadTwo
Thread ThreadOne. Incrementer: l
Thread ThreadTwo. Incrementer: 2
Thread ThreadOne. Incrementer: 3
Thread ThreadTwo. Incrementer: 4
Thread ThreadOne. Incrementer: 5
Thread ThreadTwo. Incrementer: 6
Thread ThreadOne. Incrementer: 7
Thread ThreadTwo. Incrementer: 8
Thread ThreadOne. Incrementer: 9
Upotreba lokota
Iako je objekt InterLocked prikladan kad elite poveati ili smanjiti vrijednost, postojat
e situacije kad ete htjeti kontrolirati pristup i drugim objektima. Dakle potreban je
opi mehanizam za sinkronizaciju. U C # to prua znaajka lock.
Lock oznaava kritian dio koda pruajui sinkronizaciju zadanom objektu dok lokot
djeluje. Sintaksa znaajke lock je da se za objektu zatrai lokot i zatim izvede iskaz ili
blok iskaza. Lokot se uklanja na kraju bloka iskaza.
C # prua izravnu podrku za lokote s pomou kljune rijei lock. Proslijedite refe-
rencu na objekt i nakon kljune rijei dodajte blok iskaza:
lock(izraz) blok iskaza
{
int temp;
lock (this)
{
temp = counter;
temp ++;
Thread.Sleep(l);
counter = temp;
}
// Pridruuje uveanu vrijednost
/ / i prikazuje rezultat
Console.WriteLine(
"Thread {o}. Incrementer: {l}",
Thread.CurrentThread.Name,
temp);
}
}
484 | Programiranje C#
Catch i finally blokovi i ostatak koda su nepromijenjeni u odnosu na prethodni primjer.
Izlaz ovog koda je identian onom koji je nastao koritenjem Interlocked klase.
Upotreba monitora
Objekti koje smo do sada koristili bit e dovoljni za veinu potreba. Meutim, za naj-
softiciranije upravljanje resursima, moda ete htjeti koristiti monitor. Monitor vam
preputa da odluite kad poeti i prestati sa sinkronizacijom i omoguava da ekate
dok drugi dio koda ne postane slobodan.
Kad poelite poeti sa sinkronizacijom, pozovite Enter() metodu monitora,
prosljeujui objekt koji elite zakljuati:
Monitor.Enter(this);
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
#endregion
namespace UsingAMonitor
{
class Tester
{
private long counter = 0;
II Pokree dretve
int ctr = l;
foreach ( Thread myThread in myThreads )
{
myThread.IsBackground = true;
myThread.Start();
myThread.Name = "Thread" + ctr.ToStringO;
ctr++;
Console.WriteLine( "Started thread {0}", myThread.Name );
Thread.Sleep( 50 );
486 | Programiranje C#
Primjer 20-4. Upotreba objekta Monitor (nastavak)
}
void Decrementer()
{
try
{
// Sinkronizira ovaj dio koda
Monitor.Enter( this );
void Incrementer()
{
try
{
Monitor. Enter( this );
while ( counter < 1 0 )
{
}
finally
nje s radom.
488 | Programiranje C#
Ponovno napiite i Decrementer mijenjajui iskaz i f u iskaz while u i sputajui vrijed-
nost sa deset na pet:
//if (counter < 10)
while (counter < 5 )
Krajnji uinak ovih dviju promjena je da Thread2, Incrementer, poalje signal metodi
Decrementer nakon svakog uveavanja. Dok je vrijednost manja od pet Decrementer
mora ekati. Kad vrijednost bude vea od pet Decrementer se izvodi do kraja. Kad je
gotova, dretva Incrementer moe nastaviti s izvoenjem. Izlaz je prikazan ovdje:
[Thread2] In Incrementer. Counter 2
[Threadl] In Decrementer. Counter 2. Cotta Wait!
[Thread2] In Incrementer. Counter 3
[Threadl] In Decrementer. Counter 3. Gotta Wait!
[Thread2] In Incrementer. Counter 4
[Threadl] In Decrementer. Counter 4. Cotta Wait!
[Thread2] In Incrementer. Counter 5
[Threadl] In Decrementer. Counter 4.
[Threadl] In Decrementer. Counter 3.
[Threadl] In Decrementer. Counter 2.
[Threadl] In Decrementer. Counter 1.
[Threadl] In Decrementer. Counter 0.
[Thread2] In Incrementer. Counter 1
[Thread2j In Incrementer. Counter 2
[Thread2] In Incrementer. Counter 3
[Thread2] In Incrementer. Counter 4
[Thread2] In Incrementer. Counter 5
[Thread2] In Incrementer. Counter 6
[Thread2] In Incrementer. Counter 7
[Thread2] In Incrementer. Counter 8
[Thread2] In Incrementer. Counter 9
[Thread2] In Incrementer. Counter 10
Stanje natjecanja
Pretpostavite da imate dvije dretve i da je jedna odgovorna za otvaranje datoteke, a druga
za pisanje u datoteku. Vano je da nadzirete drugu dretvu tako da bude osigurano da je
prva dretva otvorila datoteku prije nego to nastupi druga dretva. U nekim uvjetima prva
dretva e otvoriti datoteku pa e druga dretva dobro raditi. Pod nekim nepredvienim
okolnostima, prva dretva nee moi dovriti otvaranje datoteke prije nego druga dretva
pokua upisati u nju i bit e izbaena iznimka (ili jo gore, program e se blokirati). To je
stanje nadmetanja i moe biti vrlo komplicirano otkriti pogreke koje do njega dovode.
Zastoj
Dok ekate da resurs postane slobodan postoji rizik da nastane zastoj (engl. deadlock ) koji
se uprogramerskim krugovima naziva i smrtonosni zagrljaj (engl. deadly embrace). Kad
nastane zastoj dvije ili vie dretve ekaju jedna drugu i nijedna se ne moe osloboditi.
Pretpostavimo da imate dvije dretve, ThreadA i ThreadB. ThreadA zakljua objekt
Employee i onda pokuava staviti lokot za red u datoteci. Ispada da je ThreadB ve
zakljuala taj red pa ThreadA eka.
Na nesreu, ThreadB ne moe aurirati red dok ne otkljua objekt Employee, koji je ve
zakljuala dretva ThreadA. Nijedna od dretvi ne moe nastaviti i nijedna dretva nee
otkljuati svoj resurs. ekaju jedna drugu u smrtonosnom zagrljaju.
Kao to je opisano, zastoj je lako uoiti i ispraviti. U programu koji izvodi mnogo
dretvi, zastoj moe biti teko uoiti, a kamoli ispraviti. Jedna smjernica je da dobijete
sve lokote koje trebate ili da oslobodite sve lokote koje imate. To jest, im ThreadA
uvidi da ne moe zakljuati red Row, trebala bi otkljuati objekt Employee. Slino, kad
ThreadB ne moe zakljuati objekt Employee, trebala bi osloboditi red Row. Druga vana
smjernica je da zakljuate to je mogue manji dio koda i da drite lokot to je krae
mogue.
490 | Programiranje C#
POGLAVLJE 21
Tokovi podataka
Krajnja toka toka najee je pomono spremite. Pomono spremite osigurava izvor
za tok, kao to jezero moe biti izvor rijeke. Pomono spremite je najee datoteka,
ali to moe biti i mrea ili Web konekcija.
D atoteke i mape su u .N ET kosturu apstrahirane klasama. Te klase pruaju metode i
svojstva za stvaranje, imenovanje, brisanje i ostale operacije s datotekama i mapama
na disku.
491
Datoteke i mape
Prije nego to vidimo kako moemo prebaciti podatke u datoteke ili iz datoteka, prou-
imo podrku za upravljanje datotekama i mapama u .NET-u.
Klase koje trebate se nalaze u System.I0 imenskom prostoru. Meu njima je i File
klasa koja predstavlja datoteku na disku te Directory klasa koja predstavlja direktorij
(u Windowsima se direktorij naziva mapa).
Rad s mapama
Directory klasa izlae statike metode za stvaranje, prebacivanje i pretraivanje mapa.
Sve metode klase Directory su statike pa ih moete pozvati bez instance klase.
Klasa DirectoryInfo je slina klasi Directory samo to ne sadri nita osim lanova
instance (to jest, uope nema statikih lanova). DirectoryInfo izvodi iz FileSystem-
Info koja izvodi iz MarshalByRefObject. Klasa FileSystemInfo ima vei broj svojstava i
metoda koje pruaju informacije o datoteci ili mapi.
Tablica 21-1 sadrava popis najvanijih metoda klase Directory a tablica 21-2 popis
najvanijih metoda DirectoryInfo klase, ukljuujui vana svojstva i metode naslje-
ene od FileSystemInfo.
M e to d a U p o tre b a
CreateDirectory() Stvara sve m ape i podm ape zadane p ara m etrom putanje.
Attributes Nasljeuje od klase F i l e S y s t e m I n f o . U zim a ili postavlja a trib u te tre n utn e datoteke.
492 | Programiranje C#
Tablica 21-2. Najvanije metode i svojstva Directorylnfo klase (nastavak)
To vraa polje DirectoryInfo objekata od kojih svaki predstavlja mapu. Istu metodu
moete ponavljati prosljeujui joj sve DirectoryIivfo objekte:
fo r e a c h ( D ir e c t o r y In f o n e w D ir i n d ir e c to r ie s )
{
d ir C o u n t e r + + ;
using System;
using System.Collections.Generic;
using System.I0;
using System.Text;
#endregion
namespace RecursingDirectories
{
class Tester
{
// Statike varijable lanice za praenje ukupnih vrijednosti
// razina uvlaenja
static int dirCounter = l;
static int indentLevel = -l; // Prvi pomak je = 0
t.ExploreDirectory( dir );
494 | Programiranje C#
Primjer 21-1. Prolazak kroz podmape (nastavak)
"\n\n{o} directories -found.Nn",
dirCounter );
}
Program poinje tako da identificira sistemsku korijensku mapu (System Root, obino
C:\WinNT ili C:\Windows) i napravi DirectoryInfo objekt za nju. Zatim poziva Explo-
reDirectory prosljeujui taj DirectoryInfo objekt. ExploreDirectory prikazuje infor-
macije o mapi i onda uzima sve podmape.
Popis svih podmapa trenutne mape se dobija pozivanjem GetDirectories metode. Ona
vraa polje DirectoryInfo objekata. ExploreDirectory je rekurzivna metoda. Svaki
DirectoryInfo objekt je dalje proslijeen u ExploreDirectory. Uinak je da se rekur-
zivno pristupi svakoj podmapi i zatim iz nje izae kako bi se pristupilo ostalim podma-
pama dok ne budu prikazane sve podmape u %SystemRoot%. Kad ExploreDirectory
konano vrati pozivajua metoda ispisuje saetak.
M e to d a U p o treb a
496 | Programiranje C#
Tablica 21-4. Metode i svojstva Filelnfo klase (nastavak)
M o v e T o () Javna m etoda koja prebacuje datoteku na novu lokaciju. Moe se koristiti za m ijenjanje
im ena datoteke.
O p e n T e x t() Javna m etoda koja stvara S t r e a m R e a d e r koji ita iz postojee tekstualne datoteke.
Primjer 21-2 je modificirani primjer 21-1 u koji je dodan kod koji uzima Filelnfo objekta
za svaku datoteku iz svake podmape. Taj objekt se koristi za prikazivanje imena dato-
teke zajedno s njenom veliinom te datumom i vremenom zadnjeg pristupanja.
using System;
using System.Collections. Ceneric;
using System.I0;
using System.TeXt;
# endregion
namespace ExploringFilesAndSubdirectories
{
cla ss Tester
{
t.ExploreDirectory( dir );
Console.WriteLine(
"\n\n{0} files in {1} directories found.Nn",
H le C o u n te i , dirCounter ); \
}
// Pokree ju sa directoryInfo objektom.
// Za svaku mapu koju pronae rekurzivno
// e se pozvati.
private void ExploreDirectory( DirectoryInfo dir )
{
indentLevel++; // Pomie razinu mape
498 | Programiranje C#
Primjer 21-2. Ispitivanje datoteka i podmapa (nastavak)
// Uzima sve mape iz tekue mape
// i rekurzivno poziva ovu metodu za svaku
DirectoryIrrfo[] directories = dir.GetDirectories();
foreach ( DirectoryInfo newDir in directories )
{
dirCounter++; // Poveava broja
ExploreDirectory( newDir );
}
indentLevel--;
}
}
}
Izlaz (odlomak):
[0] WIND0WS [9/4/2004 8:37:13 AH]
Mijenjanje datoteka
Kao to moete vidjeti iz tablica 21-3 i 21-4, mogue je koristiti Filelnfo klasu za stva-
ranje, kopiranje, brisanje i mijenjanje imena datoteka. Sljedei primjer stvara novu
podmapu, kopira datoteke u nju, nekima mijenja imena, neke brie i zatim brie cijelu
mapu.
*4
Da biste postavili ovaj primjer napravite mapu Vest i kopirajte mapu
Media iz W inN T ili Windows mape u nju. Nemojte raditi sa datote-
kama u sistemskoj korijenskoj mapi. Kad radite sa sistemskim datote-
kama morate biti posebno oprezni.
Sad moete iterirati kroz mapu test i kopirati datoteke u napravljenu podmapu:
FileInfo[] filesInDir = dir.GetFiles();
foreach (Filelnfo file in filesInDir)
{
string fullName = newSubDir.FullName +
"\\" + file.Name;
file.CopyTo(fullName);
Console.WriteLine("{0} copied to newTest",
file.FullName);
}
Obratite pozornost na sintaksu metode CopyTo. To je metoda F ile ln fo objekta. Prosli-
jedite joj punu putanju nove datoteke ukljuujui ime i nastavak imena.
Kad ste kopirali datoteke moete dobiti popis datoteka u novoj podmapi i izravno
raditi s njima:
filesInDir = newSubDir.GetFiles();
foreach (Filelnfo file in filesInDir)
{
Napravite obinu cjelobrojnu varijablu counter i upotrijebite ju da promijenite ime
svake druge datoteke:
if (counter++ %2 == 0)
{
file.MoveTo(fullName + ".bak");
Console.WriteLine("{0} renamed to {l}",
fullName,file-FullName);
}
Promijenite ime datoteke tako to ete ju premjestiti u istu mapu, ali sa drugim ime-
nom. Naravno, moete premjestiti datoteku u novu mapu s originalnim imenom. Isto-
vremeno moete premjestiti datoteku i promijeniti joj ime.
Promijenite ime svake druge datoteke i pobriite one kojima niste promijenili imena:
file.DeleteO;
Console,WriteLine("{0} deleted.",
fullName);
Kad ste gotovi s datotekama moete poistiti za sobom tako to ete pobrisati cijelu
podmapu:
newSubDir.Delete(true);
500 | Programiranje C#
Primjer 21-3. Stvaranje podmape i rad s datotekama
ttregion Using directives
using System;
using System.Collections.Generic;
using System.I0;
using System.Text;
ttendregion
namespace CreatingSubdirectoryManipulatingFile
{
cla ss Tester
{
public s ta tic void Main()
{
/ / Stvara instancu i pokree ju
Tester t = new T e ste r();
string theDirectory = @"c:\test\media;
DirectoryInfo dir = new DirectoryInfo( theDirectory );
t.ExploreDirectory( dir );
}
i f ( counter++ % 2 == o )
{
file.MoveTo( fullName + ".bak" );
Console.WriteLine( "{0} renamed to {l}",
fullName, file.FullName );
}
else
{
file.Delete();
Console.WriteLine( "{0} deleted.",
fullName );
}
}
Izlaz (odlomak):
c:\test\media\Bach's Brandenburg Concerto No. 3.RMI
copied to newTest
c:\test\media\Beethoven's 5th Symphony.RMI copied to newTest
c:\test\media\Beethoven's Fur Elise.RMI copied to newlest
c:\test\media\canyon.mid copied to newTest
c:\test\media\newTest\Bach's Brandenburg Concerto
No. 3.RMI renamed to
c:\test\media\newTest\Bach's Brandenburg Concerto
No. 3.RMI.bak
c:\test\media\newTest\Beethoven's 5th Symphony.RMI deleted.
c:\test\media\newTest\Beethovens Fur Elise.RMI renamed to
c:\test\media\newTest\Beethoven's Fur Elise.RMI.bak
c:\test\media\newTest\canyon.mid deleted.
502 | P r o g r a m i r a n je C#
Tablica 21-5. Najvanije klase .NET kostura za ulaz i izlaz podataka
Klasa U p o tre b a
B in a r y R e a d e r / B in a ry W r ite r ita i pie ifrirane nizove i primitivne tipove podataka iz nizova i u nizove.
Binarne datoteke
Ovaj dio poinjemo koritenjem osnovne klase Stream za binarno itanje datoteke.
Izraz binarno itanje (engl. binary read) se koristi za razlikovanje od tekstualnog ita-
nja (engl. text read). Ako niste sigurni da datoteka sadri samo tekst, najsigurnije je
da postupate s njom kao da je tok bajtova, odnosno binarna datoteka.
P o g l a v l je 2 1 : T o k o v i p o d a t a k a | 503
Uitavanje se nastavlja sve dok vie ne bude bajtova za itanje:
while ( (bytesRead =
inputStream.Read(buffer,0,SIZE_BUFF)) > 0 )
{
outputStream.Mrite(buffer,0,bytesRead);
}
P r i m j e r 2 1 - 4 . I m p l e m e n t i r a n j e b in a r n o g i t a n j a i u p is iv a n ja u d a t o t e k u
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
#endregion
namespace ImplementingBinaryReadMriteToFile
{
class Tester
{
const int SizeBuff = 1024;
// Datoteka za upisivanje
Stream outputStream = File.OpenWrite(
@"C:Vtest\source\testl.bak" );
504 I P r o g r a m i r a n je C #
Primjer 21-4. Implementiranje binarnog itanja i upisivanja u datoteku (nastavak)
I I nastavlja ih zapisivati u izlazni tok
while ( ( bytesRead =
inputStream.Read( buffer, 0 , SizeBuff ) ) > o )
{
outputStream.Write( b u f f e r , 0, bytesRead ) ;
}
Rezultat izvoenja ovog programa kopija ulazne datoteke (testl.cs ) u istoj mapi s ime-
nom testl.bak. Moete usporediti nastale datoteke koritenjem alata za usporeivanje
datoteka. Datoteke su identine, kao to se vidi na slici 21-1.'
Comparison Results 1
IDENTICALFIlES: C:\test\soufce\tesl1.cs. C:\te$t\soiifce
\test1.bak
Tokovi s m e u sp rem n ic im a
U prethodnom primjeru napravili ste meuspremnik u koji e se uitavati podaci. Kad
ste pozvali Read() jedan puni meuspremnik je uitan s diska. Meutim, operacijski
sustav e biti uinkovitiji ako bude uitavao vei (ili manji) broj bajtova odjednom.
Meni najdrai alat za usporedbu datoteka je ExamDiff Pro. (h ttp://w w w .p restosoft.com lp s.asp p ag e-ed p
ex am d iffp ro).
P o g la v lje 2 1 : T o k o v i p o d a ta k a | 505
najuinkovitijim. Va meuspremnik ipak e napuniti u koliinama koje zadate, ali iz
meuspremnika u memoriji a ne izravno iz pomonog spremita. Krajnji uinak je da
su ulaz i izlaz uinkovitiji i prema tome bri.
Kad imate obian tok proslijedite nejgov objekt konstruktoru toka s meuspremnikom:
Bu ff er ed St re am buffered lnpu t =
new Bu ff er ed Stream(i np ut Strea m) ;
Bu ff er ed St re am buffered Outpu t =
new Bu ff er e d St re am ( o ut pu t S t re am );
Sada moete koristiti BufferedStream kao obian tok, pozivajui Read() i Write () ba kao
to ste prije napravili. Operacijski sustav obrauje pohranjivanje u meuspremnik:
whil e ( (bytesRead =
bu ff er ed ln pu t. Rea d(buffe r,0 ,SIZE_ B UFF)) > 0 )
{
bu f f e r e d O u t p u t .Writ e( bu ff er , 0 , b y t e s R e a d ) ;
}
P r im j e r 2 1 - 5 . lm p l e m e n t i r a n j e u l a z a i i z l a z a p r e k o m e u s p r e m n i k a
class Test er
{
const int Si ze Bu ff = 1024;
506 | P r o g r a m i r a n je C#
Primjer 21-5. Implementiranje ulaza i izlaza preko meuspremnika (nastavak)
public static void Main()
BufferedStream bufferedOutput =
new BufferedStream(outputStream);
byte[] buffer = new Byte[SizeBuff];
int bytesRead;
while ( (bytesRead =
bufferedlnput.Read(buffer,o,SizeBuff)) > o )
bufferedOutput.Write(buffer,0,bytesRead);
bufferedOutput.Flush();
bufferedlnput.Close();
bufferedOutput.Close();
}
}
S veim datotekama ovaj primjer bi se trebao izvoditi bre nego primjer 21-4.
Da biste napravili StreamReader instancu prvo napravite Filelnfo objekt i onda pozo-
vite OpenText() metodu na njemu;
P o g la v lje 2 1 : T o k o v i p o d a ta k a | 507
Filelnfo theSourceFile =
new Filelnfo (@"C:\test\source\testl.cs");
OpenText () vraa StreamReader za datoteku. Kad imate StreamReader moete itati dato-
teku red po red:
do
{
text = stream.ReadLine();
} while (text != nuli);
ReadLine() uitava po jedan red sve dok ne doe do kraja datoteke. StreamReader e
vratiti nuli kad doe do kraja datoteke.
Da biste napravili StreamWriter klasu pozovite StreamWriter konstruktor prosljeujui
mu puno ime datoteke u koju elite upisivati:
Streamklriter writer = new
StreamWriter((s>"C:\ test\source\folder3.bak", false);
Drugi parametar je logiki argument append. Ako datoteka ve postoji, true e izazvati
da se novi podaci dodaju na kraju datoteke, a false e pisati preko postojee datoteku.
U ovom sluaju proslijedite false tako da pie preko datoteke ako ve postoji.
Sad moete napraviti petlju za ispisivanje sadraja svih redova stare datoteke u novu
datoteku i na konzolu:
do
{
text = reader.ReadLine();
writer.WriteLine(text);
Console.WriteLine(text);
} while (text != nuli);
using System;
using System.Collections.Ceneric;
using System.I0;
using System.Text;
#endregion
namespace ReadingWritingToTextFile
{
class Tester
{
public static void Main()
{
// Stvara instancu i pokree ju
508 | P r o g r a m i r a n je C#
P r im je r 21-6. Uitavanje iz tekstualne datoteke i ispisivanje u tekstualnu datoteku (nastavak)
Tester t = new Tester();
t .Run();
// Pospremanje
reader.Close();
writer.Close();
} '
I }
}
Kad se ovaj program pokrene sadraj originalne datoteke se ispisuje na zaslon i upisuje
u novu datoteku. Pogledajte sintaksu za ispisivanje na konzolu:
Console.WriteLine(text)j
Kljuna razlika je u tome d aje WriteLine() metoda od Console statika, dok je Write-
Line() metoda od StreamWriter, koja je nasljeena od TextWriter, metoda instance i
mora biti pozvana na objektu, a ne na klasi.
P o g l a v l je 2 1 : T o k o v i p o d a t a k a | 509
Asinkroni ulaz i izlaz
Svi programi koje ste dosad razmatrali izvode s i n k r o n i u la z i i z l a z podataka, to znai
da su sve druge aktivnosti zaustavljene dok program uitava ili ispisuje podatke. Pohra-
njivanje podataka u meuspremnik ili uitavanje iz njega moe (relativno govorei)
dugo potrajati, posebno ako je pom ono spremite spor disk ili (jo gore) izvor na
Internetu.
Ako radite s velikim datotekama, ili kad uitavate ili ispisujete preko mree, htjet ete
a s i n k r o n i u l a z i i z l a z p o d a t a k a koji omoguava da zaponete uitavanje i okrenete se
drugim stvarima dok C LR ispunjava va zahtjev. .N ET kostur prua asinkroni U/l s
pomou BeginRead() i BeginWrite() metoda Stream klase.
Pored tri parametra koje ste koristili kod binarnog uitavanja (meuspremnik, pomak
1broj bajtova koji se uitavaju), BeginRead() trai jo d e l e g a t a i o b j e k t s t a n ja .
a
Ovo je instanca openitijeg asinkronog predloka koji se susree diljem
.N ET kostura (na primjer, asinkroni ulazno/izlazni tok, asinkrone rad-
<' A
it,' nje s pristupnim tokam a, asinkroni poziv delegata itd.).
I
Delegat je opcionalna metoda s povratnim pozivom koja se, ako je pruena, poziva
prilikom uitavanja podataka. Stanje je takoer neobavezno. U ovom primjeru, prosli-
jedite nuli za stanje. Stanje objekta se uva u varijablama lanicama probne klase.
Moete slobodno staviti bilo koji objekt u param etar stanja i moete ga uzeti prilikom
povratnog poziva. Obino (kao to moete pretpostaviti iz imena) sauvate vrijedno-
sti stanja koje ete trebati prilikom vraanja. Projektant programa Parametar stanja
moe koristiti projektantu da spremi stanje poziva (pauzirano, nedovreno, izvodi se,
i tako dalje).
U ovom primjeru, napravite meuspremnik i Stream objekt kao privatne varijable lanice:
public class AsynchIOTester
{
private Stream inputstream;
private byte[] buffer;
corist int BufferSize = 256;
510 I P r o g r a m i r a n je C#
public delegate void AsyncCallback (IAsyncResult ar);
Prema tome, ovaj delegat moe biti povezan s bilo kojom metodom koja vraa void i
uzima IasyncResult suelje kao parametar. CLR e proslijediti IasyncResult suelje
prilikom izvoenja, kad je metoda pozvana. Vi samo trebate deklarirati metodu:
void OnCompletedRead(IAsyncResult asyncResult)
Evo kako to radi, korak po korak. U Main() metodi napravite instancu klase i pokre-
nite ju:
public static void Main()
{
AsynchIOTester theApp = new AsynchIOTester();
theApp.Run();
}
Onda radite neto drugo dok uitavanje traje. U ovom sluaju simulirajte koristan rad
brojanjem do 5 0 0 0 0 0 prikazujui napredak nakon svakih 1 00 0 brojeva:
for (long i = 0; i < 500000; i++)
{
if (i%iooo == 0)
P o g la v lje 2 1 : T o k o v i p o d a ta k a | 511
{
Console.WriteLine("i: {0}", i);
}
}
Prva stvar koju trebate uiniti kad vam bude javljeno da je uitavanje zavreno je da
odredite koliko je bajtova zapravo uitano. Uinite to pozivanjem metode EndRead() \z
Stream objekta, prosljeujui joj IAsyncResult suelje koje je proslijedio C L R :
int bytesRead = inputStream.EndRead(asyncResult);
EndRead() vraa broj uitanih bajtova. Ako je taj broj vei od nula, pretvorit ete sadr-
aj meuspremnika u niz znakova i ispisati ga na konzolu i onda ponovno pozvati
BeginRead() za novo asinkrono uitavanje:
if (bytesRead > o)
{
String s =
Encoding.ASCII.CetString (buffer, 0, bytesRead);
Console.WriteLine(s);
inputStream.BeginRead(
buffer, 0, buffer.Length,
myCallBack, nuli);
}
Sada moete raditi neto drugo dok se podaci uitavaju, ali moete upravljati uitanim
podacima (u ovom sluaju, ispisivanjem na konzolu) svaki put kad je meuspremnik
pun. Primjer 21-7 sadri kompletan program.
using System;
using System.Collections.Generic;
using System.I0;
using System.Text;
#endregion
namespace AsynchronousI0
{
public class AsynchIOTester
{
private Stream inputStream;
// Delegirana metoda
private AsyncCallback myCallBack;
512 | P r o g r a m i r a n je C #
Primjer 21-7. Implementacija asinkronog ulaza i izlaza podataka (nastavak)
I I Veliina meuspremnika
const int BufferSize = 2 5 6 ;
// Konstruktor
AsynchIOTester()
{
// Otvara ulazni tok
inputStream =
File.OpenRead(
@"C:\test\source\AskTim.txt'' );
// Dodjeljuje meuspremnik
buffer = new byte[BufferSize];
void Run()
{
inputStream.BeginRead(
buffer, // uva rezultate
0, // Pomak
buffer.Length, // (BufferSize)
myCallBack, // Delegat povratnog poziva
nuli ); // Lokalni objekt stanja
// Povratna metoda
void OnCompletedRead( IAsyncResult asyncResult )
{
int bytesRead =
P o g l a v l je 2 1 : T o k o v i p o d a t a k a | 513
Primjer 21-7. Implementacija asinkronog ulaza i izlaza podataka (nastavak)
inpiitStream.EndRead( asyncResult ) ;
Iz la z (odlomak):
i : 47000
i : 48000
i : 49000
Date: lanuary 2001
From: Dave H eisler
To: Ask Tim
S u b ject: Ouestions About 0 'R e i l ly
Dear Tim,
I 'v e been a programmer fo r about ten y ears. I had heard of
0 ' R eilly b o o k s.th en .. .
Dave,
You might be amazed at how many requ ests fo r help with
school p ro jeets I g e t;
i : 50000
i : 51000
i: 52000
514 I P r o g r a m i r a n je C#
podataka stvorenih koritenjem pristupnih toaka. Pristupne toke su vrlo korisne
za aplikacije koje se temelje na pristupu klijent-posluitelj, za aplikacije za izravnu
razmjenu datoteka (engl. peer to peer) i prilikom pozivanja udaljenih procedura. Pri-
stupna toka je objekt koji predstavlja krajnju toku za komunikaciju izmeu procesa
koji komuniciraju preko mree. One mogu raditi s raznim protokolima, ukljuujui
UDP i TCP. U ovom dijelu stvaramo TCP/IP vezu izmeu posluitelja i klijenta. TCP/
IP je konekcijski protokol slian toku podataka koji se koristi za mrenu komunika-
ciju. Konekcijski znai da koritenjem TCP/IP protokola kad je veza uspostavljena dva
procesa mogu komunicirati kao da su povezani izravno telefonskom linijom.
at >
Iako je TCP/IP napravljen za komunikaciju preko mree, moete simuli-
ran mrenu komunikaciju izvoenjem dva procesa na istom raunalu.
Ako program koristite u mrei koja ima vatrozid, pitajte administratora mree koji ulazi su zatvoreni.
P o g la v lje 2 1 : T o k o v i p o d a ta k a | 515
Moete zamisliti da napravite najjednostavnijeg sluatelja na svijetu, koji strpljivo eka
klijentov poziv. Kad primi poziv, meudjeluje s tim klijentom iskljuujui sve druge
klijente. Sljedeih nekoliko klijenata koji pozovu e se spojiti, ali e automatski biti
stavljeni na ekanje. Dok ovi sluaju ugodnu glazbu i dok im se govori da je njihov
poziv vaan i da e biti obraen kad dou na red, oni e uzalud gubiti vrijeme u svo-
jim dretvama. Kad se red za ekanje popuni, sljedei pozivatelji e dobiti isti signal
ili signal da je zauzeto. Moraju onda prekinuti i ekati da naa jednostavna pristupna
toka zavri s trenutnim klijentom. Ovaj model dobro funkcionira za posluitelje koji
primaju jedan ili dva zahtjeva tjedno, ali se ne prilagoava dobro stvarnim situacijama.
Veina posluitelja treba obraivati tisue, ak i desetke tisua zahtjeva u minuti!
Da bi obraivale velik broj veza, aplikacije koriste asinkroni ulaz i izlaz da prihvate
poziv i stvore pristupnu toku s vezom prema klijentu. Originalni sluatelj se onda
vraa oslukivanju, ekajui sljedeeg klijenta. Aplikacija tako moe obraivati mnogo
poziva. Svaki put kad je poziv prihvaen, nova pristupna toka je stvorena.
Klijent nije svjestan ovog trika kojim je nova pristupna toka stvorena. to se tie kli-
jenta, spojio se na IP adresu i port koji je traio. Primjetite da nova pristupna toka uspo-
stavlja vezu s klijentom. To je potpuno drukije nego kod UDP protokola koji koristi
protokol bez veze. Kod TCP/IP protokola, kad je veza uspostavljena, klijent i posluitelj
znaju kako komunicirati meusobno, a da ne moraju ponovno adresirati svaki paket.
AcceptSocket metoda od TcpListener objekta vraa Socket objekt koji predstavlja sue-
lje Berkeley pristupne toke (engl. Berkeley socket interface) i koji je povezan na odre-
enu krajnju toku. AcceptSocket() je sinkrona metoda koja nee vratiti dok ne primi
zahtjev za vezu.
<*,
Poto je model iroko prihvaen od strane prodavaa raunala, Berke-
ley pristupne toke ine jednostavnijim zadatak prebacivanja izvornog
f' koda temeljenog na pristupnim tokama iz Windows i U nix okoline.
Kad imate pristupnu toku spremni ste poslati datoteku klijentu. Napravite Net-
morkStream klasu, prosljeujui konstruktoru pristupnu toku:
516 | P r o g r a m i r a n je C #
NetuorkStream networkStream = new NetworkStream (socketForClient);
Onda napravite StreamWriter objekt kao to ste to uinili ranije, osim to ovaj put ne
na datoteci, nego na NetworkStream klasi koju ste upravo napravili:
System .IO.Stream W riter stream klriter = new
System .IO.Stream W riter(networkStream );
Kad ispisujete u ovaj tok podataka, tok se alje preko mree do klijenta. Primjer 21-8
prikazuje cijeli posluitelj (Ogolio sam ovaj posluitelj do sutine. Kod stvarnog poslu-
itelja gotovo sigurno biste izvodili kod za obradu zahtjeva u dretvi i obuhvatili logiku
u tr y blok kako biste obradili mrene probleme).
using System;
using Sy stem .C ollections.G en eric;
using System.Net;
using System .N et.Sockets;
using System .Text;
# endregion
namespace NetworkStreamingServer
{
public c la s s NetuorklOServer
{
P o g l a v l je 2 1 ; T o k o v i p o d a t a k a | 517
Primjer 21-8. Implementacija posluitelja za mreni tok podataka (nastavak)
// Poziva pomonu metodu za s la n je datoteke
Send FileToC lient( socketForC lient ) ;
Console.W riteLine(
"D isconnecting from c l i e n t . . . " ) ;
// is t i i ide kui
S o ck etF o rC lie n t.C lo se();
C onsole.W riteLine( " E x i t i n g . . . " );
break;
}
}
st rin g th e S trin g ;
// I t e r i r a kroz datoteku i a l je
// k lije n tu red po red
do
{
th e S trin g = stream Reader.ReadLine();
i f ( th e S trin g != n u li )
{
C onsole.W riteLine(
"Sendlng { 0 } " , th e S trin g ) ;
stream W riter.W ritel_ine( th e S trin g ) ;
stream W rlter.Flu sh ();
}
}
while ( th e S trin g != n u li ) ;
// Posprema
stream R eader.Close();
networkStream .Close( ) ;
stream W riter.C lose();
}
}
}
518 | P r o g r a m i r a n je C #
Izrada klijenta za mreni tok podataka
Klijent instancira TcpClient klasu koja predstavlja klijentovu TCP/IP vezu s poslui-
teljem:
Tcp Client socketForServer;
socketForServ er = new Tcp C lient("lo calH ost", 65 0 0 0 ) ;
Sad uitavajte tok podataka dok god u njemu ima podataka, aljui izlaz na konzolu:
do
{
outputString = StreamReader.ReadLine();
i f ( outputString != n uli )
{
Co nsole.W riteLine(outputString);
}
}
w hile( outputString != n uli ) ;
using System;
using System .C ollections.G eneric;
using System .Net.Sockets;
using System .Text;
# endregion
namespace NetworkStreamingClient
{
pu blic c la s s Client
{
try
{
socketForServer =
new TcpClient( "localH ost", 65000 ) ;
P o g l a v l je 2 1 : T o k o v i p o d a t a k a I 519
Primjer 21-9. Implementiranje klijenta za mreni tok podataka (nastavak)
}
catch
{
Console.WriteLine(
"F ailed to connect to serv er at { 0 } :6 5 0 0 0 " ,
" lo c a lh o st " ) ;
retu rn ;
}
try
{
s t rin g ou tpu tStrin g;
i f ( ou tpu tString != n u li )
{
Console.W riteLine( outputString ) ;
}
}
while ( ou tpu tString != n u li ) ;
}
catch
{
Console.WriteLine(
"Exception reading trom Server" ) ;
}
// Pospremanje
netw orkStream .Close();
}
}
}
520 | P r o g r a m i r a n je C #
Izlaz posluitelja:
C lien t connected
Sending This is lin e one
Sending This is lin e two
Sending This is lin e three
Sending This is lin e four
Disconnecting trom C l i e n t . . .
E x it in g .. .
Iz la z k l i je n t a :
Tijelo Run() metode za posluitelj je vrlo slino onom koje ste vidjeli u primjeru 21-8.
;Prvo napravite sluatelja i onda pozovite Start (). Zatim napravite beskonanu petlju
i pozovite AcceptSocket(). Kad je pristupna toka spojena, umjesto da obradite vezu
jnapravite novi ClientHandler i pozovite StartRead() na tom objektu.
P o g la v lje 2 1 : T o k o vi p o d a ta k a | 521
Kompletan izvorni kod za posluitelj je prikazan u primjeru 21-10.
using System;
using Sy stem .C ollections.G en eric;
using System.Net;
using System .N et.Sockets;
using System .Text;
ttendregion
namespace AsynchNetworkServer
{
pu blic c la ss AsynchNetworkServer
{
c la s s ClientHandler
{
p riv a te b y te[] b u ffer;
p riv ate Socket Socket;
p riv ate NetworkStream networkStream;
p riv ate AsyncCallback callbackR ead ;
p riv ate AsyncCallback callb ack W rite;
callbackRead =
new AsyncCallback( this.OnReadComplete ) ;
callback W rite =
new AsyncCallback( this.OnW riteCom plete ) ;
}
// Zapoinje it a n je niza od k l i je n t a
pu blic void StartR ead()
{
networkStream.BeginRead( b
u ffe r, 0, b u ffer.Length ,
callbackRead, n u li ) ;
}
522 j P r o g r a m i r a n je C #
Primjer 21-10. Implementirale asinkronog posluitelja za mreni tok podataka (nastavak)
i f ( bytesRead > o )
{
st rin g s =
System.Text.Encoding. ASCII. GetString(
b u ffer, o, bytesRead ) ;
Console.W rite(
Received { 0 } bytes from C lien t: { l } 1',
bytesRead, s ) ;
networkStreara.BeginWrite(
b u ffer, o, bytesRead, callbackW rite, nu li V
}
e lse
{
Console.W riteLine( "Read connection dropped ) ;
networkStream .Close();
Socket.Close();
netmorkstream = nuli;
Socket = n u li;
}
}
networkStream.EndWrite( ar ) ;
C onsole.W riteLine( "Write complete );
networkStream.BeginRead(
b u ffer, o, bu ffer.Length,
callbackRead, n uli ) ;
}
}
P o g la v lje 2 1 : T o ko v i p o d a ta k a I 523
P r im je r 2 1 - 1 0 . I m p l e m e n t i r a n j e a s in k r o n o g p o s lu i t e l j a z a m r e n i t o k p o d a t a k a ( n a s t a v a k )
P r im je r 2 1 - 1 1 . I m p l e m e n t a c i j a k l i j e n t a z a a s i n k r o n i u l a z / i z l a z p o d a t a k a p r e k o m r e e
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
#endregion
namespace AsynchNetworkClient
{
public class AsynchNetworkClient
{
private NetworkStream streamToServer;
524 | P r o g r a m i r a n je C#
Primjer 21-11. Implementacija klijenta za asinkroni ulaz!izlaz podataka preko mree (nastavak)
AsynchNetworkClient c l ie n t =
new AsynchNetworkClient();
return C lien t.R u n ();
AsynchNetworkClient()
U Stvara streamWriter i k o r is t i ga
!! za zapisiv an je niza na p o slu ite lj
System .IO.Stream Writer w riter =
new System.IO.Stream W riter( streamToServer )
w riter.W riteLin e( message ) ;
w rite r.F lu sh ();
Iz la z ( p o s lu i t e l j) :
C lien t connected
Received 22 bytes from c l ie n t : Hello Programming C#
Write complete
^ Read connection dropped
Izlaz ( k l i je n t ) :
Connecting to lo calh o st
Sending Hello Programming C# to serv er.
Received: Hello Programming Ctt
u ovom primjeru mreni posluitelj se ne blokira dok obrauje veze s klijentima ali
p epusta upravljanje nm vezama instancama ClientHandler. Klijenti ne bi smjeli osje-
titi kanjenje dok posluitelj obrauje njihove veze. J
P o g l a v l je 2 1 : T o k o v i p o d a t a k a | 525
Asinkroni tok datoteka preko mree
Sad moete kombinirati znanja koje ste stekli o asinkronom itanju datoteka i asinkro-
nim mrenim tokovima da biste napisali program koji isporuuje datoteku klijentu
na zahtjev.
callbackRead =
new AsyncCallback(this.OnReadCom plete);
callback W rite =
new A syncC allback(th is. OnWriteComplete);
Sad imate ime datoteke. S njim moete otvoriti tok podataka u datoteku i koristiti isto
asinkrono uitavanje koje je koriteno u primjeru 21-7:
526 I P r o g r a m i r a n je C#
inputStream =
File.OpenRead(fileName);
inputStream.BeginReadj
buffer, // uva rezultate
0, // Pomak
buffer.Length, // Veliina meduspremnika
myFileCallBack, // Delegat povratnog poziva
nuli); // lokalni objekt stanja
Ovo uitavanje datoteke ima vlastiti povratni poziv koji e biti upuen kad ulazni tok
uita puni meuspremnik iz datoteke s posluiteljevog diska.
// Ispisuje na klijenta
networkStream.BeginWrite(
buffer, o, bytesRead, callbackWrite, nuli);
Ako je OnFileCompletedRead pozvana i nita nije ucitano onda to znai da je cijela dato-
teka poslana. Posluitelj reagira zatvaranjem NetworkStream objekta i pristupne toke
dajui na taj nain do znanja klijentu da je transakcija gotova:
networkStream.Close();
Socket.Close();
networkStream = nuli;
Socket = n u li;
networkStream.EndWrite(ar);
Console.WriteLine( "Write complete");
inputStream.BeginRead(
buffer, // uva rezultate
0, // Pomak
buffer.Length, // (BufferSize)
myFileCallBack, // Delegat povratnog poziva
nuli); // Lokalni objekt stanja
P o g l a v l je 2 1 : T o k o v i p o d a t a k a I 527
Ciklus ponovno poinje s drugim uitavanjem datoteke i nastavlja se sve dok datoteka
ne bude potpuno uitana i poslana klijentu. Klijentov kod jednostavno ispisuje ime
datoteke u mreni tok da pokrene uitavanje datoteke:
s t rin g message = @ "C:\test\source\AskTim .txt";
System .IO.Stream W riter w riter =
new System .IO .Stream W riter(stream ToServer);
w riter.W rite(m essage);
w r it e r .F lu s h ();
Klijent onda zapoinje petlju itajui iz mrenog toka sve dok posluitelj vie ne poa-
lje ni jedan bajt. Kad je posluitelj gotov, mreni tok podataka se zatvara. Ponite inici-
jaliziranjem Boolean vrijednosti na fa lse i stvaranjem meuspremnika za prihvaanje
bajtova koje poalje posluitelj:
bool fO uit = f a l s e ;
while ( ! fO u it)
{
ch ar[] b u ffer = new c h a r[B u ffe r S iz e j;
Poziv Read() metode uzima tri parametra: meuspremnik, pomak od kojeg poinje
itanje i veliinu meuspremnika:
in t bytesRead = re a d er.R ea d (b u ffer,0 , B u ffe r S iz e );
Provjerite da lije Read() vratila bajtove. Ako nije, gotovi ste i moete postaviti Boolean
vrijednost fOuit na true i tako prekinuti izvoenje petlje:
i f (bytesRead == 0)
fOu it = tru e ;
Ako ste primili bajtove, moete ih ispisati na konzolu ili u datoteku ili moete uiniti
to god elite s vrijednostima koje je posluitelj poslao.
e ls e
{
s t rin g th e S trin g = new S t rin g ( b u f fe r ) ;
C o n so le.W rite L in e(th e Strin g);
}
}
S28 I P r o g r a m i r a n je C #
Primjer 21-12. Implementiranje asinkronog mrenog posluitelja datoteka
# region Using d irectiv e s
using System;
using System. C o llectio n s.C e n e ric;
using System .I0;
using System.Net;
using System .N et.Sockets;
using System .Text;
# endregion
namespace AsynchNetworkFileServer
{
pu blic c la s s AsynchNetworkFileServer
{
c la s s ClientHandler
{
p riv ate const in t Bu fferSize = 2 5 6 ;
p riv ate b yte[] b u ffer;
p riv ate Socket Socket;
p riv ate NetworkStream networkStream;
p riv ate Stream inputStream;
p riv a te AsyncCallback callbackRead;
p riv ate AsyncCallback callback W rite;
p riv ate AsyncCallback m yFileCallBack;
// Konstruktor
pu blic ClientHandler(
Socket socketForC lient )
{
// I n i c i ja l i z i r a n je v a r ija b le la n ice
Socket = socketForC lient;
// I n i c i ja l i z i r a n je meuspremnika
// za uvanje datoteka
bu-ffer = new b y te[2 5 6 ];
P o g la v lje 2 1 : T o k o v i p o d a ta k a | 529
Primjer 21-12. hnplementiranje asinkronog mrenog posluitelja datoteka (nastavak)
I I u mreni tok
callbackNrite =
new AsyncCallback( this.OnWriteComplete );
// Osvjeava konzolu
Console.Write(
"Opening file {o}", fileName );
}
else
{
Console.WriteLine( "Read connection dropped" );
networkStream.Close();
Socket.Close();
networkStream = nuli;
Socket = nuli;
5B0 | P r o g r a m i r a n je C #
Primjer 21-12. Implementiranje asinkronog mrenog posluitelja datoteka (nastavak)
}
}
P o g l a v l je 2 1 ; T o k o v i p o d a t a k a I 531
Primjer 21-12. Implementiranje asinkronog mrenog posluitelja datoteka (nastavak)
IPAddress localAddr = IPAddress.Parse( "127.0.0.1" );
TcpListener tcpListener = new TcpListener( localAddr, 65000 );
tcpListener.Start();
AsynchNetworkClient Client =
new AsynchNetworkClient();
return Client.Run();
AsynchNetworkClient()
{
string serverName = "localhost";
Console.WriteLine(Connecting to {0}", serverName);
TcpClient tcpSocket = new TcpClient(serverName, 65000);
streamToServer = tcpSocket.CetStreain();
}
532 | P r o g r a m i r a n je C #
Primjer 21-13. Implementirale klijenta asinkronog mrenog posluitelja datoteka (nastavak)
{
string message = l"C:\test\source\AskTim.txt ;
Console.Write(
"Sending {0 } to server.", message);
// Odgovor itanja
System.IO.StreamReader reader =
new System.IO.StreamReader(streamToServer);
Web tokovi
Umjesto itanja iz toka podataka koji prua posluitelj, moete jednako lako itati s
bilo koje Web stranice na Internetu.
P o g l a v l je 2 1 : T o k o v i p o d a t a k a I 533
WebRequest je objekt koji zahtijeva resurs koji se identificira s pomou URI adrese, to
je slino U RL adresi Web stranice. Moete koristiti WebRequest objekt da napravite
WebResponse objekt koji e uahuriti objekt na koji pokazuje URI. To jest, moete
pozvati GetResponse() na WebRequest objektu da bi dobili pristup objektu na koji poka-
zuje URI. Ono to se vraa je uahureno u WebResponse objekt. Onda od WebResponse
objekta moete traiti Stream objekt pozivanjem metode GetResponseStream(). GetRe-
sponseStream() vraa tok podataka koji uahuruje sadraj Web objekta (na primjer,
toka podataka s Web stranicom).
Sljedei primjer vraa sadraj Web stranice kao tok podataka. Da bi pribavili Web stra-
nicu, trebat ete koristiti HttpWebRequest. HttpWebRequest izvodi iz WebRequest i prua
dodatnu podrku za rad s H T T P protokolom.
Da biste napravili HttpWebRequest, pretvorite tip WebRequest objekta koji ste dobili od
statike C reate() metode iz WebRequestFactory:
HttpWebRequest WebRequest =
(HttpWebRequest) WebRequest.Create
("http://www.libertyassociates.com/book_edit.htm'1);
C reate() je statika metoda objekta WebRequest. Kad joj proslijedite U RI, stvara se
instanca HttpWebRequest.
Stvaranje HttpWebRequest objekta uspostavlja vezu prema Web stranici. Ono to dobi-
jete natrag od posluitelja je uahureno u HttpWebResponse objekt koji je H TTP pot-
klasa openitije WebResponse klase:
HttpWebResponse WebResponse =
(HttpNebResponse) WebRequest.GetResponse();
Moete itati iz tog toka podataka ba kao to ste itali iz mrenog toka podataka.
Primjer 21 -14 sadri kompletan ispis.
using System;
using System.Collections.Generic;
using System.I0;
using System.Net;
534 | Programiranje C#
P r im je r 21-14. itanje Web stranice kao toka H T M L podataka (nastavak)
using System.Net.SocketS;
using System.Text;
Sendregion
namespace ReadingWebPageAsHTML
// Stvara WebRequest z a o d r e e n u s t r a n i c u
HttpWebRequest WebRequest =
( HttpWebRequest ) WebRequest.Create
( ''http://www.libertyassociates.com/");
// U z i m a streamReader od odgovora
StreamReader streamReader = new StreamReader(
MebResponse.GetResponseStream(), Encoding.ASCII );
try
{
string outputstring;
outputstring = streamReader.ReadToEnd();
Console.WriteLine( outputstring );
catch
{
Co"sole.WriteLine( "Exception reading trom Web page" );
streamReader.Close();
}
}
}
Izlaz (odlomak):
<html>
<head>
<title>Liberty Associates</title>
<meta http-equiv="Content-Type content="text/html; charset=iso-8 8 5 9 -i>
<scnpt language="lavaScript>
<!--
isNS=(navigator.appName=="Netscape");
activeMenu="";
activelndex=-l;
activelmg="
window.onError = nuli;
function setImage(imgName,index) {
if(activeImg==imgName)
return true;
document.imagesfimgName].src = rolloverIirig[index] .src;
-return true;
}
rolloverImg=new Array();
Izlaz pokazuje da se kroz tok podataka alje H TM L stranica koju ste traili. Mogli
biste koristiti ovu mogunost za analizu stranica: uitavanje stranice s Weba u meu-
spremnik i izvlaenje sam o nekih potrebnih informacija.
*4
Svi primjeri analize Web stranica u ovoj knjizi pretpostavljaju da
podatke uitavate uz dozvolu autora.
Serijalizacija
Kad se objekt ispisuje na disk njegovi podaci moraju biti serijalizirani (engl. serialized)
- to jest, ispisani u tok podataka kao niz bajtova. Objekt e takoer biti serijaliziran
kod spremanja u datoteku ili prilikom rasporeivanja u drugi kontekst, aplikacijsku
domenu, proces ili preko granica izmeu raunala.
CLR prua podrku za serijalizanje objekta i svih podataka lanova objekta. Kao to
je istaknuto u poglavlju 19, tipovi se ne mogu serijalizirati. Da biste mogli serijaliziran
objekt morate ga eksplicitno oznaiti [S e ria liz a b le ] atributom.
CLR e obaviti serijalizaciju objekta za vas. Poto C L R zna kako serijalizirati sve pri-
mitivne tipove, ako se objekt sastoji samo od njih, spremni ste za serijalizaciju. Ako se
objekt sastoji i od drugih tipova (klasa) koje je definirao korisnik, morate osigurati da
se i ti tipovi mogu serijalizirati. CLR e pokuati erijatiirati svaki objekt koji se nalazi
unutar vaeg objekta (i sve njihove objekte), ali ovi objekti moraju biti ili osnovni tipovi
ili tipovi koje je mogue serijalizirati.
Ovo je takoer bilo evidentno u poglavlju 19 kad ste rasporeivali Shape objekt koji
je sadravao P o in t objekt kao podatak lan. P o in t objekt se sastojao od primitivnih
podataka. Da biste serijalizirali (i rasporedil) Shape objekt, njegov sastavni dio, Point
objekt, je takoer trebao biti oznaen tako da se moe serijalizirati.
536 | Programiranje C#
Upotreba formatera
Kad su podaci serijalizirani vjerojatno e ih netko itati, bilo isti program ili neki drugi
program na istom ili drugom raunalu. U svakom sluaju, kod koji ita podatke oe-
kuje da podaci budu u odreenom formatu. U veini .N ET aplikacija oekivani format
je ili binarni format ili SOAP format.
Kad imate instancu formatera moete pozvati metodu S e ria liz e f) prosljeujui joj tok
podataka i objekt za serijalizaciju. U sljedeem primjeru vidjet ete kako se to radi.
Upotreba serijalizacije
Da biste vidjeli kako radi serijalizacija trebate pokusnu klasu koju moete serijalizirati
i zatim deserijalizirati. Moete poeti stvaranjem klase SumOf. Ona ima tri varijable
lanice klase:
private int startNumber = l;
private int endNumber;
private int[] theSums;
Konstruktor za SumOf objekt uzima dvije cjelobrojne vrijednosti: poetni broj i zavrni
broj. On ih dodjeljuje lokalnim vrijednostima i poziva pomonu metodu da izrauna
sadraj polja:
Serijaliziranje objekta
Sad oznaite klasu za serijaliziranje atributom [S e ria liz a b le ]:
[Serializable]
class SumOf
Da biste pokrenuli serijalizaciju prvo trebate fileStream objekt u kojeg ete serijalizirati
SumOf objekt:
FileStream fileStream =
new FileStream("DoSum.out",FileMode.Create);
Sad ste spremni da pozovete metodu S e ria liz a b le () formatera, prosljeujui tok poda-
taka i objekt za serijalizaciju. Budui da se to izvodi u metodi SumOf, moete proslijediti
th is objekt koji ukazuje na trenutni objekt:
binaryFormatter.Serialize(fileStream,this);
Deserijalizacija objekta
Da biste ponovno sloili objekt, otvorite datoteku i zatraite da ju binarni formater
deserijalizira metodom D e S erialize():
538 | Programiranje C#
public static SumOf DeSerialize()
{
FileStream fileStream =
new FileStream("DoSum.out",FileMode.Open);
BinaryFormatter binaryFormatter =
new BinaryFormatter();
SumOf retVal = (SumOf) binaryFormatter.Deserialize(fileStream);
fileStream.Close();
return retVal;
}
Da biste bili sigurni da sve radi, prvo instanci raj te novi objekt tipa SumOf i zatraite da
se serijalizira. Zatim stvorite novu instancu tipa SumOf pozivanjem statikog deserijali-
zatora i zatraite da prikae svoje vrijednosti:
public static void Main()
{
Console.WriteLine("Creating first one with new...");
SumOf app = new SumOf(l,1 0 );
Console.WriteLine(
"Creating second one with deserialize...
SumOf newlnstance = SumOf.DeSerialize();
newInstance.DisplaySums();
}
using System;
using System.Collections.Generic;
using System.I0;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
ttendregion
namespace SerializingDeserialingAnObject
[Serializable]
class SumOf
{
private int startNumber = l;
private int endNumber;
private int[] theSums;
Console.Write( "Serializing..." );
// Stvara tok datoteke za zapisivanje datoteke
FileStream fileStream =
new FileStream( "OoSum.out", FileMode.Create );
U Koristi binarni formater CLR-a
BinaryFormatter binaryFormatter =
new BinaryFormatter();
// Serijaliziranje na disk
binaryFormatter.Serialize( fileStream, this ),
Console.WriteLine( "...completed" );
fileStream.Ciose();
}
540 | Programiranje C#
Primjer 21-15. Serijaliziranje i deserijaliziranje objekta (nastavak)
BinaryFormatter binaryFormatter =
new BinaryFormatter();
SumOf retVal = ( SuraO-f ) binaryFormatter.Oeserialize( fileStieam
fileStream.Close();
return retVal:
Izlaz:
Creating first one with new...
l,
1,
6,
10,
15,
21,
28,
36,
45,
55,
Serializing.... completed
Creating second one with deserialize...
1,
3,
6,
10,
15,
21,
28,
36,
45,
55,
Izlaz prikazuje d aje objekt napravljen, prikazan i zatim serijaliziran. Objekt je nakon
toga deserijaliziran i ponovno prikazan, bez gubitka podataka.
Meutim, ako ne serijalizirate polje, objekt kojeg napravite nee biti valjan kad ga dese-
| rijalizirate. Polje e biti prazno. Zapamtite, kad deserijalizirate objekt, jednostavno ga
itate iz serijaliziranog oblika i ne koriste se metode.
Ova implementacija moe biti vrlo jednostavna. Samo zatraite od objekta da ponovno
izrauna nizove:
public virtual void OnDeserialization (Object sender)
{
ComputeSums();
}
Ovo je klasian ustupak izmeu vremena i prostora na disku. Ako ne serijalizirate
polje deserijalizacija e biti neto sporija (jer morate ponovno izraunati polje), ali e
datoteka biti neto manja. Da bih provjerio jesmo li bez serijaliziranja polja postigli
kakav uinak, pokrenuo sam program s brojevima od 1 do 5 0 0 0 . Prije nego to sam
postavio atribut [NonSerialized] za polje, serijalizirana datoteka je imala 20K. Nakon
postavljanja atributa [NonSerialized], datoteka je imala 1K. Nije loe. Primjer 21-16
prikazuje izvorni kod koji koristi brojeve od jedan do pet kao ulaz (da pojednostav-
nimo izlaz).
using System;
using System.Collectlons.Generic;
using System.I0;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
#endregion
namespace WorkingWithNonSerializedObject
{
[Serializable]
class SumOf : IDeserializationCallback
{
private int startNumber = l;
private int endNumber;
[NonSerialized]
private int[] theSums;
542 | Programiranje C#
P rim je r 21-16. R ad sa ne se rija lizira nim objektom {nastavak)
{
Console.WriteLine("Creating first one with new.
SumOf app = new Sum0f(i,5); );
startNumber = start;
endNumber = end;
ComputeSums();
DisplaySums();
Serialize();
theSums[i] = j + theSums[i-i];
foreach(int i in theSums)
Console.WriteLine("{o}, ",i);
C onsole.W rite("Serializing...
// Stvara t o k za zapisivanje datoteke
FileStream fileStream =
new FileStream("DoSum.out",FileMode.Create);
// Koristi binarni formater CLR-a
8inaryFormatter binaryFormatter =
new BinaryFormatter();
H Serijaliziranje na disk
binaryForm atter.Serialize(fileStream ,this)-
C o n s o l e . WriteLine(..completed);
^ fileStream.Close();
{
FileStream fileStream =
new FileStream( "DoSum.out",FileHode.Open);
BinaryFormatter binaryFormatter =
new BinaryFormatter();
SumOf retVal = (SumOf) binaryFormatter.Deserialize(fileStream);
fileStream .Close.O;
return retVal;
}
Output:
Creating first one with new...
1,
3,
6,
10,
15,
Serializing.... completed
Creating second one with deserialize...
1,
3,
6,
10,
15,
Moete vidjeti u izlazu da su podaci uspjeno serijalizirani na disk i zatim ponovno
sastavljeni deserijalizacijom. Ustupak izmeu vremena i prostora na disku nema puno
smisla s pet vrijednosti, ali ima ako koristite pet milijuna vrijednosti.
Dosad ste tok podataka slali na disk da biste ga pohranili i preko mree da biste
lake komunicirali s udaljenim programim a. Postoji jo jedan sluaj kad biste mogli
napraviti tok podataka: da biste spremili stalnu konfiguraciju i podatke o statusu za
pojedinane korisnike. .N E T kostur za ovu svrhu prua izolirano spremite (engl. iso-
lated storage).
Izolirano spremite
.N E T C L R prua izolirano spremite da bi om oguio projektantima aplikacija da
pohrane podatke o korisnicima. Izolirano spremite prua veinu funkcionalnosti
uobiajenih .ini datoteka ili novijeg H K EY _C U R R E N T_U SE R kljua u Registryju.
Najee ete pohraniti tekst, esto u obliku parova ime-vrijednost. Izolirano spre-
mite je dobar mehanizam za spremanje informacija o korisniku kao to su korisniko
ime, poloaj raznih prozora i programa te drugi podaci specifini za aplikaciju i kori-
snika. Podaci se pohranjuju u zasebnu datoteku za svakog korisnika, ali mogu biti
izolirane jo vie tako da se dijele prema raznim aspektima identiteta koda (po sklopu
ili po aplikacijskoj domeni kojoj pripadaju).
Zatim upisujte u taj tok kao to biste u bilo koji drugi. Primjer 21-17 to prikazuje.
using System;
using System.Collections.Generic;
using System.I0;
using System.IO.IsolatedStorage;
using System.Text;
#endregion
namespace HritingToIsolatedStorage
{
public class Tester
{
string theEntry;
do
546 | Programiranje C#
{
theEntry = reader.ReadLine();
Console.WriteLine(theEntry);
} while (theEntry != nuli);
Console.WriteLine(theEntry);
Izolirano spremite je ogranieno sklopom (tako da, ako zatvorite program i kasnije
ga ponovno pokrenete, moi ete proitati konfiguraciju datoteke koju ste napravili,
ali neete moi itati konfiguraciju ni jednog drugog sklopa). Primjer 21-18 prua
metodu potrebnu za itanje datoteke. Zamijenite Run() metodu u prethodnom pri-
mjeru, ponovno prevedite i pokrenite program (ali nemojte mijenjati ime jer nee moi
pristupiti izoliranom spremitu koje ste prethodno napravili).
reader.Close();
i ' configFile.Close();
J: }
| Output:
I Last access: 5/2/2001 10:00:57 AM
Last position = 27,35
Programeri vole imati istu situaciju. Iako bi bilo zgodno kad bi mogli odbaciti sav kod
koji smo ikad napisali i poeti iznova, to nije prihvatljiva opcija za veinu kompanija.
Tijekom proteklog desetljee mnoge razvojne tvrtke su puno investirale u razvoj i kup-
nju COM komponenata i ActiveX kontrola. M icrosoft se obvezao da e osigurati da
se ove zastarjele komponente mogu koristiti unutar .N ET aplikacija i (moda manje
vano) da se .N E T komponente mogu jednostavno pozivati iz COM objekata.
548
Stvaranje ActiveX kontrole
Da biste prikazali mogunost koritenja klasine ActiveX kontrole u .N ET aplikaciji
)
prvo napravite jednostavan kalkulator s etiri funkcije kao Act,veX kontrolu i zatim
I T v , ACtln tr? ' U iZ C # aPlikacje- NaPiite kontrolu na VB6 jeziku i ispi-
tajte ju u VB6 aplikaciji. Ako nemate VB6 ili se ne elite gnjaviti stvaranjem kontrole,
zete preuzeti kontrolu s moje Web stranice (http://www.LibcrtyAssodates.com ).
i
I Kad kontrola bude radila u standardnom Windows okoliu uvest ete ju u vau apli-
kaciju temeljenu na Windows Forms obrascima.
nroibik ? M
apravili k0ntr,lu r ite VB6 1 0daberite A ct'eX Control kao tip novog
i p rojek t^ Napravite: projektni obrazac to je mogue manji jer ova kontrola nee imati
isnicko suelje. Pritisnite desnom tipkom mia na UserControll i odaberite Proper-
zon, p T ! r teiJ J ' me U Calculat0r u Prozoru Properties. Odaberite Project u pro-
. J Explorer, a u Properties prozoru promijenite ime u CalcControl. Odmah
snimite projekt pa datoteku i projekt nazovite CalcControl, kao na slici 22-1.
\
.
3
Sad moete dodati etiri funkcije kalkulatora tako to ete desnom tipkom mia priti-
snuti CalcControl obrazac, odabrati View Code s kontekstnog izbornika i upisati VB
kod prikazan u primjeru 22-1.
Public Function
Subtract(left As Double, right As Double)
As Double
Subtract = left - right
End Function
Public Function
Multiply(left As Double, right As Double)
As Double
Multiply = left * right
End Function
Public Function
Divide(left As Double, right As Double)
As Double
. Divide = left / right
End Function
Ovo je sav kod za kotrolu. Prevedite ga u CalcControl.ocx datoteku tako to ete oda -
brati File - Make C alcControl.ocx s izbornika.
Cortiobjoeaflrs| InMttafcfeOtocoj
: - ) VldeoSoft vs F lex 3 C ontrols
O A i v e Setup C ontroi Llb ra r/
A d o b e SVG Vtow er Type L t o rv y 2 .0
AxBrowse
C:lW ZNN T\System 32lm sconf.cS
G C :\W lN N T \S ys tem 32 \tdc .oo:
Bal
C d lg
CJ C D T od 1.0 Type U b ra r/
c ertm ap OLE C ontroi m odule
C e rtW te Activ eK C ontroi m odule
G ctc 1 . 0 T y p e L to e ry
enfgprts OLE C ontroi m odde
ii P. SeietedhemsOniy
refcontrd
. Idcatiori: C{\..;\22-!..\Adi^CekCon^.(>cx
550 | Programiranje C#
To stavlja novu kontrolu na paletu s alatima, kao to je prikazano na slici 22 -3 (zao
krueni dio).
Dajte gumbima imena btnAdd, b tn S u b tra ct, btn M ultiply i btn D ivide. Sve to preostaje
je da implementirate metode za obradu pritiska na gumbe kalkulatora. Svaki put kad
je gumb pritisnut elite uzeti vrijednosti iz dva polja za tekst, prebaciti ih u double
(kako zahtijeva CalcControl) koristei VB6 CDbl metodu, pozvati C alcC ontrol metodu
i ispisati rezultate u natpisu.
End Sub
/'Forml.cs^'totml.cs[Design]*XConsolej .L ."//
552 | Programiranje C#
Uvoenje kontrola
Postoje dva naina za uvoenje ActiveX kontrolu u Visual Studio 2 0 0 5 razvojni oko-
li: moete koristiti Visual Studio alate ili moete uvesti kontrolu runo s pomou
aximp pomonog programa koji se isporuuje s .N ET SDK kosturom. Da biste koristili
Visual Studio 2 0 0 5 odaberite Tools - Choose ToolboxItems s izbornika. Otvara se
dijaloki okvir. Na kartici COM Components naite CalcControl.Calculator objekt
koji ste upravo registrirali (slika 2 2 -6 ).
G : \ > a .x in ji c a .I o o o n t r u 1 . oc>
r a t od ft a r o n it J y : Ci: \(/ c Criii t l'n 1 . d l 1
(io n e r a t ori ft r a v n i ) I y * G \ft> ioCun t.ro l.d J 1
mm
flife a 2 2 -7 . P rogram axim p
CalcControl.dll
Posrednika .N ET biblioteka klasa
AxCalcControl.pdb
Datoteka za otkrivanje pogreaka
Kad je to uinjeno moete se vratiti u Choose Toolbox Items prozor, ali ovaj put oda-
berite .N ET Framework Components. Sad moete potraiti lokaciju na kojoj je .NET
Windows kontrola AxCalcControl.dll stvorena i uvesi tu datoteku na paletu s alatima,
kao to je prikazano na slici 2 2 -8 .
. 0 A d R c- Desfcop : CakControi.dll
0 Appe
0 Asse
I H _
HyProjects
F fte r
. pAccesst
My Computer
Ftenarpe. p
3 I ~ QP i-' .1
, J l f e o f t y p e [Executables 3 Cancd L
554 | Programiranje C#
% VScrollBar
WebBrowser
8 CalcCoritrol.Calculator
Sad moete povui ovu kontrolu na Windows Forms obrazac i koristiti njene metode,
ba kao to ste radili u VB6 primjeru.
Dodajte metode za obradu dogaaja za svaki od etiri gumba. One e delegirati svoj
posao ActiveX kontroli koju ste napisali u VB6 i uvezli u .NET.
P rim je r 22 -3 . Im plem entiranje metoda za obradu dogaaja za pro bn i W indow s Forms obrazac.
private void btnAdd_Click(object sender, System.EventArgs e)
{
double left = double.Parse(textBoxl.Text);
double right = double.Parse(textBox2 .Text);
labell.Text = axCalculatorl.Add( ref left, ref right).ToStringO;
Prvi korak je da napravite novi ActiveX DLL projekt. To je nain na koji VB6 stvara
standardne CO M DLL-ove. Nazovite klasu Com Calc, a projekt Com Calculator. Spre-
mite datoteku i projekt. Kopirajte metode iz primjera 2 2 - 4 u prozor s kodom.
Public Function
Subtract(left As Double, right As Double)
As Double
Subtract = left - right
End Function
Public Function
Multiply(left As Double, right As Double)
As Double
Multiply = left * right
End Function
Public Function
Divide(left As Double, right As Double)
As Double
Divide = left / right
End Function
556 | Programiranje C#
t o, * 05
Avsfebte Refefebiest
Kod ranog povezivanja (engl. early binding) pronalaenje adrese metode na posluitelju
se odvija prilikom prevoenja projekta klijenta, kad se metapodaci dodaju u klijentov
modul. Kod kasnog povezivanja (engl. late binding) adresa se ne pronalazi sve do izvo-
enja, kada COM ispituje posluitelj da li podrava metodu.
Runo uvoenje
Zaponite kopiranjem ComCalculator.dll datoteke u .N E T okoli i registriranjem s
pomou Regsvr32. Tada ste spremni za uvoenje CO M objekta u .N E T s pomou
programa Tlblmp.exe. Sintaksa ovog postupka je da unesete ime CO M komponente,
a nakon njega opcionalno ime rezultirajue datoteke, kao to je prikazano na slici
22 - 12.
558 ] Programiranje C#
Slika 22 -12 . Program T lblm p.exe
Ako odluite ne uvoziti runo biblioteku, uvezite je kroz IDE. Da biste to uinili,
odaberite COM karticu u dijalokom okviru Add Reference i zatim registrirani COM
objekt, kao to je prikazano na slici 22-13.
'i
Time e Tlblmp biti pozvan za vas i kopirat e rezultirajui RCW u mapu C:\Docu-
ments and Settings\Administrator\Application Data\Microsoft\VisualStudio\RCW.
Meutim, morat ete biti oprezni jer DLL koji je nastao ima isto ime kao COM DLL.
U svakom sluaju moete napraviti korisniko suelje slino onom koritenom za ispra-
bavanje ActiveX kontrole (slika 22-14).
't'lrSifliact { |. tvldei Vi %
,fceW ( ^ v#v . v
* i- >
Sve to je preostalo jest da napiete metode za obradu dogaaja za etir. gumba, kao
u primjeru 2 2 -6 .
r , , 2 2 -6 , m * . a ** ia gaia,a za V E 6 C O M D L L , . obzazaa
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Oata;
using System.Drawing;
using System.Windows.Forms;
ttendregion
namespace ComDLLTest
{
partial class Formi : Form
public Forml()
InitializeComponent();
}
ComCalculatorDLLNET.ComCalc theCalc
new ComCalculatorDLLNET.ComCalc();
result = theCalc.Add( ref left, ref right );
labell.Text = result. ToStringO;
560 | Programiranje C#
P r im je r 2 2 -6 . lm p lem e ntiranje metoda za obradu dogaaja za VB6 C O M D L L testni obrazac
(nastavak)
Double left, right, result;
left = Double.Parse(textBoxl.Text);
right = Double.Parse(textBox2.Text);
ComCalculatorDLLNET.ComCalc theCalc =
new ComCalculatorDLLNET.Comalc();
result = theCalc.Subtract(ref left, ref right);
labell.Text = result.ToString();
}
Ba kao to ste vidjeli u poglavlju 18, poinjete tako da napravite Type objekt koji e
sadravati informacije o tipu comCalc:
Type comCalcType;
comCalcType = Type.GetTypeFromProgID("ComCalculator.ComCalc );
Sad moete nastaviti kao kada biste pozivali ovu metodu na klasi opisanoj u .NET
sklopu. Ponite pozivom Createlnstance da biste uzeli instancu comCalc objekta:
object comCalcObject = Activator.CreateInstance(comCalcType);
562 | Programiranje C#
osto sve etiri metode za obradu moraju ponoviti ovaj posao, s razlikom jedino u
imenu metode koju pozivaju, faktorirat ete zajedniki kod u privatnu pomonu
metodu Invoke, kako stoje prikazano u primjeru 22-7. Trebate dodati using deklara-
ciju za System. Reflection u izvornom kodu.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
ftendregion
namespace LateBinding
{
partial class Formi : Form
{
public Forml()
{
InitializeComponent();
}
Invoke( "Add" );
}
Invoke( "Subtract" );
}
Invoke( Hultiply" )
}
Invoke( "Divide" );
}
{
Double left, right, result;
left = Double.Parse( textBoxl.Text );
right = Double.Parse( textBox2.Text );
// Polje za argumente
object[] inputArguments =
{ left, right };
// Stvara instancu
object comCalcObject =
Activator.CreateInstance( comCalcType );
labell.Text = result.ToStringO;
}
}
}
Pozovite Regasm s imenom D LL-a koji m ora biti postavljen u GAC (pogledajte poglavlje
17). Na primjer:
Regasm myAssembly.dll
To e izvesti metapodatke komponente u Registry. Na primjer, moete napraviti novi
C # DLL projekt u kojem ete ponovno napraviti kalkulator s etiri funkcije, kao to
je prikazano u primjeru 2 2 -8 .
564 | Programiranje C#
P rim je r 2 2 -8 . K a lk u la to r s e tiri fu n kc ije u D L L -u
using System;
using System.Reflection;
[assembly: AssemblyKeyFile(test.key")]
namespace Programming_CSharp
{
public class Calculator
{
public Calculator()
{
}
public Double Add (Double left, Double right)
Oal-* renote] v. . n
Appfcation Confkurattan: (LstoJO) i
Syiing ------------------------
Confitm passwotd:
| OK ~] | Cancel | [ Help |
Sada moete pozvati kalkulator s etiri funkcije kao COM objekt koristei standardni
VBScript. Na primjer, moete napisati kratku Windows skriptu, poput one u primjeru
22-9.
Kad pokrenete skriptu pojavljuje se dijaloki okvir koji potvruje da je objekt napra-
vljen i pozvan (slika 22-19).
566 | P ro g ra m ira n je C#
Stvaranje biblioteke tipova
Ako elite koristiti rano povezivanje s .NET DLL-om, obino ete napraviti biblio-
teku tipova. To moete uiniti koritenjem pomonog programa TlbExp (Type Library
Export) tako to ete napisati:
TlbExp ProgrammingCSharpDLL.dll /out:Calc.tlb
Kad imate biblioteku tipova, moete uvesti klasu kalkulatora u bilo koji COM okoli.
P/Invoke
Iz jezika C # mogue je pozvati neupravljani kod (engl. unmanaged code). Obino ete
to raditi kada budete trebali postii neto to ne moete kroz FCL. Inaica 2 .0 NET-a
ini upotrebu P/Invoke jo rjeom.
| - tT ypc
yp cl rb Viewcr h e j d i
'Ffe ::'Vtew V " . > "
- :' y v i '.-':.(
:.( t.'V
t.'V-
'V-
Da biste vidjeli kako radi, pogledajte ponovno primjer 21-3. Sjetit ete se da ste koristili
Filelnfo klasu da promijenite ime datoteke pozivanjem MoveTo() metode:
DLL Name
Ime DLL-a kojeg pozivate.
EntryPoint
Pokazuje ime ulazne toke (metode) DLL-a koju se poziva.
ExactSpelling
Omoguava da CLR pronae odgovarujue metode ali s malo drugaijim ime-
nima na temelju CLR-ovog poznavanja pravila imenovanja.
CharSet
Govori kako bi znakovni argumenti metoda trebali biti rasporeeni.
SetLastError
Ako ovaj parametar postavite na true moi ete pozvati Marshal.GetLastWin32
Error i provjeriti je li dolo do pogreke prilikom pozivanja metode.
O statak koda je praktino isti, osim samog poziva metode MoveFile(). Primjetite da
je MoveFile() deklarirana da bude statika metoda klase, pa koristite semantiku sta-
tike metode:
Tester.MoveFile(file.FullName,file.FullName + ".bak");
Proslijedite izvorno i novo ime datoteke i ona e biti promijenjena, ba kao i kada ste
pozvali file.MoveTo(). U ovom primjeru nema prednosti (i postoji znatna teta) kori-
tenja P/Invoke. Napustili ste upravljani kod, a tako i sigurnost tipa pa kod vie nee
raditi u situacijama djelomine pouzdanosti*1. Primjer 22-10 prikazuje kompletan
izvorni kod za koritenje P/Invoke za mijenjanje imena datoteka.
using System;
using System.Collections.Generic;
using System.I0;
568 | P ro g ra m ira n je C#
P r i m j e r 2 2 - 1 0 . U p o t r e b a P l ln v o k e z a p o z i v a n je W in 3 2 A P l m e t o d e ( n a s ta v a k )
using System.Runtime.InteropServices;
using System.Text;
#endregion
namespace UsingPIrvoke
{
class Tester
{
if ( counter++ % 2 == 0 )
{
// P/Invoke Windows API
Tester.MoveFile( fullName, fullName + ".bak" );
Pokazivai
U knjizi jo nismo koristili pokazivae u stilu C/C++ jezika. Ova tema pojavljuje se
samo ovdje, u zadnjim odlomcima i na zadnjim stranicama knjige, iako su pokazivai
temeljni dio C obitelji jezika. U C # jeziku pokazivai su namijenjenu nestandardnom
i naprednom programiranju. Obino se koriste samo s P/Invoke.
C # podrava uobiajene C pokazivake operatore koji su opisani u tablici 22-1.
Tablica 22-1. C # p o k a z i v a k i o p e r a t o r i
Operator Znaenje
& Operator adresa od" vraa pokaziva na adresu vrijednosti.
* Ovaj operator vraa vrijednost na adresi pokazivaa.
-> Operator koji se koristi za pristupanje lanovima tipa.
570 | P ro g ra m ira n je C#
rijeima, nepouzdani kod stvara otok C++ koda unutar inae sigurne C # aplikacije,
pa kod nee raditi u situacijama djelominog povjerenja.
Da biste vidjeli primjer kada bi ovo moglo biti korisno, itajte datoteku na konzolu
upuivanjem dva W in32 API poziva: CreateFile i ReadFile. ReadFile uzima kao svoj
drugi parametar pokaziva na meuspremnik. Deklaracije dviju uvezenih metoda nije
drukija od onih u primjeru 22-11.
P r i m j e r 2 2 - 1 !. D e k l a r i r a n j e W in 3 2 A P I m e t o d a z a u v o e n je u C# p rog ra m
[011Import(''kernel32", SetLastError=true)j
static extern unsafe int CreateFile(
string filename,
uint desiredAccess,
uint shareMode,
uint attributes,
uint creationDisposition,
uint flagsAndAttributes,
uint templateFile);
Appteatttn
Corflguration: [Actrve (Oebug)
Stgnlng
Secultv ^ ^ 0 A lo w unsafe C o d e ^ )
U O pom lz e Code
Pubfch
............................. -J Eftors and V V arrtngs...................................
Build
W anm g Level: |3 3 )
Debug
Sunvess warrings: | 1
Resouces
,-Treat W artngs as & rors ...................................- - - - - -
S etthgs
N one
O s ie d f lc Warrincis | ........................................................................................................... i
O ab
-O u tput
S lik a 2 2 -2 1 . D o z v o lja v a n je u p o tr e b e n e p o u z d a n o g k o d a
572 | P ro g ra m ira n je C#
Probni program instancira APIFileReader i ASCIIEncoding objekte. Prosljeuje ime dato-
teke konstruktoru APIFileReader i zatim stvara petlju da ponavljanjem napuni meu-
spremnik pozivanjem Read() metode, koja upuuje AP1 poziv ReadFile. Vraeno je
polje bajtova i zatim pretvoreno u niz koritenjem GetString() metode ASCIIEncoding
objekta. Taj niz je prosljeen Console.Write() metodi za ispisivanje na konzoli. Kom-
pletan izvorni kod je prikazan u primjeru 22 -12 .
P r im je r 2 2 -1 2 . K o riten je p o k a z iv a a u C # p rog ra m u
using System;
us in g System.Colle ct io ns .G eneri c;
us i n g S y s t e m .R u n t i m e .I n te r o p S er vi c e s;
us in g System.Text;
flendregion
na me sp ac e Usin gP ointer s
{
class API FileRe ader
{
const uint GenericRead = 0x80000000;
const uint 0penExisting = 3;
const uint UseDefault = 0;
int fileHandle;
}
return bytesRead;
}
}
class Test
574 j P ro g ra m ira n je C#
DODATAK
C# kljune rijei
abstract
Moifikator klase koji oznaava da se iz klase mora izvoditi da bi bila instancirana.
as
Pretvara lijevi operand u tip odreen desnim operanom i vraa nuli umjesto da
izbaci iznimku ako ne uspije.
base
Varijabla koja ima isto znaenje kao i th is osim to pristupa implementaciji
osnovne klase lana.
bool
Logiki tip podataka koji moe biti true ili false.
break
Iskaz za preskakanje koji izlazi iz petlje ili bloka switch iskaza.
byte
Integralni tip podataka bez predznaka duljine jedan bajt.
case
Iskaz odabira koja definira odreeni izbor u switch iskazu,
catch
Dio try iskaza koji hvata iznimke tipa zadanog u catch.
char
Unicode znakovni tip podataka duljine dva bajta.
checked
Iskaz ili operator koji namee provjeravanje aritmetikih granica izraza ili bloka
iskaza.
cla ss
Proiriv referentni tip koji kombinira podatke i funkcionalnost u jednu jedinicu.
575
Modifikator lokalne varijable ili deklaracije polja koji pokazuje da je vrijednost
konstanta. Const se evaluira prilikom prevoenja i moe biti samo unaprijed defi-
niranog tipa.
continue
Iskaz koji preskae preostale iskaze u bloku i nastavlja prema sljedeem ponavlja-
nju petlje,
decimal
16-bitni precizni decimalni tip podataka.
default
Oznaka u switch iskazu koja odreuje koju akciju izvesti ako nijedan case iskaz
ne odgovara switch iskazu.
delegate
Tip za definiranje potpisa metode tako da instance delegata mogu drati i pozivati
metodu ili popis metoda koje odgovaraju njegovom potpisu.
Iskaz petlje za iteriranje kroz blok iskaza sve dok iskaz na dnu petlje ne evaluira
fa lse.
double
Tip podataka za realne brojeve duljine osam bajtova.
else
Uvjetni iskaz koji definira akciju koju treba poduzeti kad prethodni i f izraz eva-
luira fa lse.
enum
Vrijednosni tip koji definira skupinu imenovanih brojanih konstanti.
event . . .
Modifikator lana za polje delegata ili svojstvo koje zadaje da se moe pristupiti
samo metodama += i -= delegata.
e x p licit
Operator koji definira eksplicitno pretvaranje.
extern .
Modifikator metode koji oznaava da je metoda implementirana sa neupravljamm
kodom.
fa lse
Logiki literal.
finally
Dio iskaza try koji se izvodi uvijek kada kontrola napusti doseg bloka try.
576 | P ro g ra m ira n je C#
fixed
lng
Integralni tip podataka sa predznakom duljine osam bajtova.
new
Operator kojt poziva konstruktor na tipu, alocirajui novi objekt na gomilu ako
je taj tip referentni ili inicijalizirajui objekt ako je to vrijednosni tip vrijednosti.
Kljuna rije je preoptereena kako bi sakrila naslijeenog lana.
nuli
Literal referentnog tipa koji pokazuje da nijedan objekt nije referenciran.
object
Tip iz kojeg izvode svi drugi tipovi,
operator
Modifikator metode koji preoptereava operatore.
override
Modifikator metode koji pokazuje da metoda klase premouje virtualnu metodu
klase ili suelja.
private . .
Modifikator pristupa koji pokazuje da samo sadravajui tip moe pristupiti
lanu.
publi-Lc. ,
Modifikator pristupa koji zadaje da je tip ili lan tipa dostupan svim drugim tipo-
vima
readonly . .
Modifikator polja koji zadaje da polje moe biti dodijeljeno samo jednom u svojoj
deklaraciji ili konstruktoru svog sadravajueg tipa.
ref
Modifikator parametra koji zadaje da se parametar prosljeuje po referenci i dodje-
ljuje prije prosljeivanja metodi.
return
Iskaz za preskakanje koji izlazi iz metode i zadaje povratnu vrijednost ako metoda
vraa vrijednost.
sbyte
Integralni tip podataka sa predznakom duljine jedan bajt.
578 | P ro g ra m ira n je C#
sealed
Modifikator klase koji pokazuje da se iz klase ne moe izvoditi,
set
Ime pristupnika koji postavlja vrijednost svojstva,
short
Integralni tip podataka s predznakom duljine dva bajta.
sizeof
Operator koji vraa veliinu strukture (u bajtovima).
stackalloc
Operator koji vraa pokaziva na zadani broj vrijednosnih tipova alociranih na
stogu.
static
ushort
Integralni tip podataka bez predznaka duine dva bajta.
using
Zadaje da se tipovi iz odreenog imenskog prostora mogu koristiti bez upotrebe
punih imena tipova. Iskaz using definira doseg na ijem kraju se objekt odbacuje.
value
Ime implicitne varijable postavljene od strane set pristupnika svojstvu.
Virtual
Modifikator metode klase koji govori da metoda moe biti premoena izvedenom
klasom.
void
Kljuna rije koja se koristi umjesto tipa za metode koje nemaju povratnu vrijed-
nost.
volatile
Pokazuje da polje moe biti promijenjeno od strane operativnog sustava ili druge
dretve.
while
Iskaz petlje za iteriranje kroz blok iskaza sve dok izraz na poetku svake iteracije
ne evaluira false.
580 | P ro g ra m ira n je C#
Kazalo
Kazalo | 581
AppendFormatO, metoda (StringBuilder), 234
Access, baza podataka, primjer, 346 (File), 496
Activator, klasa, 445 (Filelnfo), 497
ActiveX, kontrole Application, klasa, DoEvcntsO metoda iz, 324
stvaranje, 549 apstraktne klase, 109, 575
uvoenje, 548 ogranienja, 112
u .NET, 552 primjer, 109-110
Add(), metoda, 386, 418 suelja u usporedbi s, 136, 152
(Dictionary), 217 apstraktne metode, 109
(List), 201 primjer, 109-110
AddRangeO, metoda (List), 201 ArgumentException, 261
ADO.NET argumenti, 68
objektni model, 341-343 dogaaja, 359
DataAdapter, 342 ArithmeticException, 253
DataReader, 343 aritmetiki operatori, 52
DataRelations, 342 as operator, 150-151, 575
DataTables i DataColumns, 342 is operator u usporedbi s, 151
DBCommand i DBConnection, 342
asinkroni U/I, 491, 510, 516
osnovne klase, 341 ASP kontrole, 367
Rows kolekcija, Data! able, 342 ASP.NET, 356-388
OLE DB Managed Provider, 346-348 C# programiranje i, 356
poetak rada s, 343-346 DataGri u, implementiranje (primjer),
povezivanje podataka, kontrole za, 349-353
404 -406
podeavanje DataSet, 353-355 ^ datoteke s kodom, 362-364
programsko popunjavanje mree
kontrole, dodavanje na Web Forms obrasce,
podataka, 352-353 365-367
pregled, 337 metode za obradu dogaaja, 359
adrcsa-od (Sr), operator, 570 posluiteljske kontrole, 365
Amazon Web usluge posluiteljske kontrole, 367
klijentska aplikacija (primjer), 383 povezivanje podataka, kontrole za, 367-377
skup alata za programere, 391 stanje posluiteljskih kontrola, 359
Amazon.com, 389 stranice s pozadinskim kodom u inaici
analiza Web stranica, 536
2 .0 ,3 5 8
analiza Web stranica, aplikacija za, 390 pregled, 357-361
analizator stranice (regularni izrazi), 233 stvaranje, 361-364
anonimne metode, 6, 293 Web kontrole, 358
aplikacije Web stranice, stvaranje (primjer), 399
klijent Web usluga ivotni ciklus, 360
izrada, 389 ASP.NET 1.1, napomena za programere
pretraivanje prema kategoriji, 408
aspx.es datoteka, 377
prikaz rezultata, 399 pozadinski kod, model, 362
konzolne, 12 aspabel, kontrola, 402
sastavljanje u cjelinu, 389 ,aspx, nastavak imena datoteke, 361-362
uvoenje ActiveX kontrola i LOM, pohranjivanje stranica korisnikog suelja
komponenata u, 548
u, 358
Windows (pogledajte Windows Forms)
Assembly, cilj atributa, 432
aplikacijske domene, 448 Assenrbly.Load(), statika metoda, 440
dogaaji, 450 AssemblyInfo.cs, datoteka, 418
dretve u usporedbi s, 451 AssemblyLoad, dogaaj, 450
konteksti, 459 AssemblyResolve, dogaaj, 450
metode i svojstva, 450 AssemblyResolver, uitavanje sklopova s
primjer, 455-458 pomou, 422
rasporeivanje objekata preko granica, 453
Atributes, svojstvo
stvaranje i upotreba, 451
(Directorylnfo), 492
AppDomain klasa, 450 (Filelnfo), 496
CreateDomainO, metoda, 451 atributi, 7, 431-447
append, argument, 508
ciljevi, 432
Append(), metoda (StringBuilder), 233
definirani, 431
prilagoeni, 433 destruktori, 81
deklariranje, 434 enum tipovi, 35
imenovanje, 434 gcnerici (C# ) u usporedbi s C++
konstruiranje, 434 predlocima, 193
primjer, 43.5 imenski prostori, 12
upotreba, 435 indekseri, 185
primjena, 433 iskaz case, 44
Autoeomplete, svojstvo tehnologije iznimke, izbacivanje, 246
Intellisense, 15 kljuna rije implicit, 123
AutoPostBack, svojstvo, 359 konstruktor za kopiranje, 75
autorska Weh stranica, 389 logiki vrijednosni tip, 25
AWSProuctData, objekt, 397 metoda Main(), 10
Axlmp, naredbeni usluni program, 548, 553 nasljeivanje, 113
auriranje baze podataka (klijent Web usluge), nepridruene varijable, 30
399 nizovi, 220, 221
pretprocesori, 61
preoptereivanja operatora, logiki parovi,
B 122
base, kljuna rije, 575 privatno ili zatieno nasljeivanje, 102
baze podataka referentni parametri, 90
definirane, 337 referentni tipovi, 24
relacijske, 337-341 strukture, 129
13eginRead(), metoda, 5 1 1 toka zarez, 10, 65
(Stream), 503, 510 uvjetni izrazi, 38
BeginWrite(), metoda (Stream), 503, 510 virtualne metode, premoivanje, 106
Berkeley suelje pristupne toke, 516 C#
beskonane petlje, 521 definicije klase, 7
bezuvjetno grananje, 37, 38 jezik
biblioteke tipova, 558 ASP.NET i, 356
bijeli prostor, 36, 50 osnove, 23-63
binarne datoteke, 503-505 pregled, 6
binarni formater, 453 kljune rijei, 575-580
binarni operatori, 121 lock, iskaz, 480
binarno itanje datoteke, 503 naredbeni prevoditelj, prevoenje Hello
BinaryFormatter, 537 World programa s pomou, 19
BinaryReader, klasa, 503 vrlo tipizirane klase kolekcija, 24
BinarySeareh(), metoda Web Forms obrasci, upotreba, 357
(List), 201 Capacity, svojstvo (List), 201, 203
(System.Array), 167 CaptureCollection, klasa, 242-244
BinaryWriter, klasa, 503 case, iskaz, 575
BindingFlags, parametar, 444 napomena za C i C++ programere, 44
bool, tipovi, 575 napomena za VB6 programere, 44
Boolean izrazi, 38 catch, iskaz, 248-253, 575
break, iskaz, 38, 50-52, 575 namjenski iskaz catch, stvaranje, 251-253
upotreba sa svvitch iskazima, 42 odmotavanje stoga poziva, 250
brisanje, operator za, napomena za C i C++ - postupak korektivnih akcija, 249
programere, 26 ChannelServices, klasa, 463
brisanje datoteka, 500 char, tip, 27, 575
brzi razvoj aplikacija, 356 Chars, polje
BufferedStream, klasa, 503, 505 (String), 224
byte, tip, 575 (StringBuilder), 233
CharSet, parametar, 568
c checked, operator, 575
ciljevi atributa, 432
C i C++ programeri, napomena za cjelobrojne vrijednosti
apstraktne klase, ogranienja u C# , 112 dijeljenje, 52
binarni operatori, 121 pretvaranje razlomaka u/iz, 126
brisanje, operator za, 26 veliine (short, int ili long), 26
K azalo ] 583
Class, cilj atributa, 432 ContainsKey(), metoda (Dictionary), 218
class, kljuna rije, 10 ContainsValue(), metoda (Dictionary), 218
Clear, obrada pritisaka 11a gumb (primjer), 320 ContextBoundObject, 461
C lear(), metoda continue, iskaz, 38, 50-52, 576
(Dictionary), 2)7 C.ontrol, klasa
(List), 201 apstraktna, stvaranje, 112
(Queue), 212 Dra\vWindow(), metoda, oznaavanje
(Stack), 214 polimorlizmom, 103
(System.Array), 167 stvaranje polja Control objekata, 103
Clone(), metoda, 221, 228 Copy, impiementiranje dogaaja gumba
(Stack), 214 (primjer), 321-324
(String), 222 sortiranje popisa odabranih datoteka, 322-324
suelje ICloneable, 73 uzimanje odabranih datoteka, 321
Close(), metoda, 83 Copy(), metoda
CLR (Common Language Runtime), 4, 5 (File), 496
asinkroni U/l, 510 (String), 223, 227
dijeljeni sklopovi i, 425 (Systein.Array), 167
glavna ili prva metoda klase, 10 CopyTo(), metoda
podrka za dretve, 471 (Filelnfo), 497, 500
pokretanje statikih konstruktora, 78 (List), 202
rasporeivanje po referenci i, 454 (Queue), 212
serijaliziranje objekata, 536 (Stack), 215, 217
CLS (Common Language Specification), 4 (String), 224
Collections, imenski prostor, 13 C o s(), metoda, 445
Columns, kolekcija (DataTable), 342 dinamiko povezivanje, 445
COM (Component Object Model) Count, svojstvo
programiranje, 548-574 (Dictionary), 217
uvoenje COM komponenata, 556 (List), 201
biblioteka tipova u .NET, 558 (Queue), 212
COM DLL-a u .NET, 558 (Stack), 214
kasno povezivanje i refleksija, 562 CreateO, metoda
testni program, stvaranje, 559 (Directorylnfo), 493
commandString, parametar, 343 (File), 496
Common Language Runtime (pogledajte CLR) (Filelnfo), 497
Common Language Specification (CLS), 4 (WebRequest), 534
Common Type System (CTS), 4 CreateChildControls(), metoda, 360-361
Compare(), metoda (String), 223, 226, 227, CreateComlnstanceFrom(), metoda
271 (Activator), 445
CompareOrdinal(), metoda (String), 223 CreateDirectory(), metoda (Directory), 492
(String), 224 CreateDomain(), metoda
CompareTo(), metoda, 200, 203, 207 (AppDomain), 450, 451
prilagoena inaica (primjer), 208 CreateFile(), metoda, 571
Component Object Model (pogledajte COM) Createlnstance(), metoda, 179, 451, 453
Concat(), metoda (String), 223, 227 (System.Array), 167
Configuration, imenski prostor, 13 Createlnstance(), metoda (Activator), 445
connectionString, parametar, 343 CreatelnstanceFrom(), metoda
Console, klasa (Activator), 445
W rite(), metoda, 49, 573 CreateSubDirectory(), metoda (Directorylnfo),
W riteLine(), metoda, 28, 509 4 9 3 ,4 9 9
Console, objekt CreateText(), metoda (File), 496
ispis teksta na monitor, 12 CreationTime, svojstvo
operator toka i, 13 (Directorylnfo), 492
const, kljuna rije, 576 (Filelnfo), 496
Constructor, cilj atributa, 432 CTS (Common Type System), 4
(List), 201 CurrentDomain, svojstvo (AppDomain), 450
(Queue), 212
(Stack), 214
584 | Kazalo
klase ThreaStart, 472
arobnjak Data Sovirce Configurator, 349 koje zahtijeva BeginReaj), 510
lanovi instance, 77 metode instance i, 276
lanovi klase, 65 pozivanje metoda delegata (primjer),
lanovi instance ili statiki lanovi, 77 272-275
statiki, 276
vieodredini, 278-281
D vieoredini, dohvat vrijednosti iz, 295-302
Data, imenski prostor, 13 asinkrono pozivanje dogaaja, 299-302
DataAdapter, objekt, 342 metode pozivanja, 299-302
DataColumn, objekti, 342 zadavanje tijekom izvedbe, 267-275
DataColumnCollection, objekti, 342 delegirane metode, runo pozivanje (primjer),
DataGrid 297-299
implementiranje (primjer aplikacije) Deletc, obrada dogaaja gumba (primjer),
404-406 324-334
ltem_Bound, metoda, 407 DeleteO, metoda
programsko popunjavanje, 352-353 (Directorylnfo), 493
DataReader, objekti, 343 (File), 496
DataRelation, objekti, 341 (Filelnfo), 497
DataRotv, objekti, 338 Dequeue(), metoda (Queue), 212
DataSet, klasa, 338, 341 Deserialize(), metoda (SoapFormatter), 470
podeavanje, 353-355 deserijalizacija, 538, 542
stvaranje DataSet, 343 primjer, 539
svojstvo Relations, 342 destruktori, 81-83
DataTable, objekti, 338, 342 dispose u usporedbi s, 82
kolekcija Rows, 342 koje ne podravaju strukture, 129
DataTableCollection, 341 deva zapis (nain imenovanja), 13, 35
datoteke, 492-502 digitalni potpisi, 426
binarne, itanje, 503-505 dijeljeni resursi, simuliranje, 480
mijenjanje, 499-502 dijeljeni sklopovi, 424
rad s, 496-499 DLL pakao i, 425
klasa Filelnfo, 496-497 inaice, 425
metode klase File, 496 izgradnja, 427
tekstualne, itanje i pisanje, 507 stvaranje jakog imena, 428
DBCommand, objekt, 342 ostali potrebni sklopovi, 430
DBConnection, objekt, 342 s vie modula, 416
decimalni tip podataka, 26, 576 dijeljenje (/), operator, 52
napomena za Java programere, 25 Dim i New, kljune rijei (VB6), 70
Declarative Referential lntegrity (DRI), 339 dinamiki nizovi, 233-234
Decrement(), metoda (lnterlocked), 483 ogranienja graninika, 234
default, kljuna rije, 576 dinamiko povezivanje, 452
DefineDynamicAssembly(), metoda dirCounter, varijabla, 493
(AppDomain), 450 Directory, klasa, 492, 503
deklarativni jezici, 339 metode, 492
deklarativno privrivanje, 572 Directory, svojstvo (Filelnfo), 496
deklarativno Web programiranje, 357 DirectoryInfo, klasa, 492, 501
Delegate, cilj atributa, 432 GetFiles(), metoda, 496
delegate, kljuna rije, 267, 576 metode, 492
(pogledajte takoer dogaaji) stvaranje instance, 493-495, 499
delegati, 7, 267-281 Directorylnfo, objekti, 314
anonimne metode, koritenje, 294 dirSub.Attributes, svojstvo, 315
dogaaji i, 282-290 Dispose(), metoda, 82, 361
implementiranje dogaaja s delegatima pozvana metodom CIose(), 83
286-289 pozvana s pomou iskaza, 38-84
rjeavanje problema s delegatima s Distributed interNet Applications (DNA),
pomou dogaaja, 289 arhitektura, 4
kao svojstva, 277 Div(), metoda, 379
DivideByZeroException, 253
K azalo | 5 85
spajanje, 475
dizajniranje aplikacija, 389
stanje natjecanja, 489-490
DLL datoteke zastoj, 489-490
COM komponente, uvaenje, 556
dijeljeni sklopovi i, 425 DRI (Declarative Referential lntegrity), 339
pozivanje funkcija s pomou P/Invoke, 567 duboka kopija, 75
dvodimenzionalna polja
sklopovi i, 414
deklariranje, 174
sklopovi s vie modula i, 416
DNA (Distributed interNet Applications), inicijali ziranje, 175-176
arhitektura, 4 pravokutno polje (primjer), 174
zupasto polje cjelobrojnih vrijednosti,
do, iskaz, 37, 576
177-179
do-whi!e, petlje, 47
dobro poznati posltiiteljski objekti, 461
registriranje, 463 E
automatsko, 54
eksplicitna implementacija suelja, 156-165
indekseri i, 188
pristup zapeaenim klasama i
redoslijed operatora, 59
s vrijednosnim tipovima, 160-165
DoEvents(), metoda (Application), 324
sakrivanje lana, 159
(pogledajte takoer delegati)
dogaaji, 281-294 selektivno izlaganje metoda, 159
eksplicitno pretvaranje, 27, 123
aplikacijske domene, 450
konverzija izmeu enum i cjelobrojnog tipa,
asinkrono pozivanje, 299 35
delegati i, 282-290
implementiranje dogaaja s pomou tipovi za raspakiravanje, 115
delegata, 286-289 element predloka stupca, 402
rjeavanje problema delegata, 289 elementi polja, 168
Delete, metoda za obradu dogaaja else, iskaz, 576
(primjer), 324-334 Emacs, ureivanje programa s, 16
dodavanje Web Forms obrascima, 372-377 Empty, polje (String), 223
event, upotreba kljune rijei s, 290-294 EndRead(), metoda, 512
EndsWith(), metoda (String), 224, 228
implementiranje dogaaja gumba Copy
Enqueue(), metoda (Queue), 212
(primjer), 321-324
klijenta Web usluge (primjer), 396 Enter(), metoda (Monitor), 485
EntryPoint, parametar, 568
objavljivanje i pretplaivanje na, 281
Enum, ciljevi atributa, 432
obrada dogaaja kontrole TreeView
(primjer), 317-320 enum, kljuna rije, 33
OnRorvDataBound, 402 enumeracije, 31, 33-35
deklariranje, 33
RorvDataBound, 407
enum, iskaz, 33
Web Forms obrasca, 358
povratni u usporedbi s nepovratnim, 359 enum tipovi, 576
pretvaranje izmeu enum i cjelobrojnog
doseg, 13
sklopovi kao granica za sadrane tipove, tipa, 35
enumeratori, popis, 33
415
varijable u petlji, 49 Environment, klasa, 314
Equals(), metoda, 113, 200
double, tip, 26, 576
kljuni objekt rjenika, 218
DrawWindow(), metoda, 22
premoivanje virtualne, 122
klase Control, oznaivanje kao virtualne,
(String), 223, 228
103
pozivanje polja objekata Control, 103 Event, cilj atributa, 432
event, kljuna rije, 576
dretve, 472-479
aplikacijske domene u usporedbi s, 451 EventArgs, klasa, 282-283
ExactSpelling, parametar, 568
pokretanje, 472-475
EXE (izvedbena datoteka)
prekidanje, 476
J1T kompilacija i, 19
sinkronizacija, 480-489
sklopovi i, 414
stanje natjecanja, 489-490
sklopovi s vie modula i, 416
upotreba lnterlocked, 482-484
upotreba lokota, 484-485 ExecuteAssembly(), metoda
(AppDomain), 450
upotreba monitora, 485-489
zastoj, 490
!
Exists(), metoda
formatirani nizovi, dodavanje, 235
(File), 496
1raction, definiranje konverzija i operatora za
(List), 202
klasu, 123-128
Exists, svojstvo Framervork Class Libra ry (FCL), 4
(DirectoryInfo), 492 imenski prostori i, 12
(Filelnfo), 496
klase Web Forms obrazaca, 358
E x it(), metoda (Monitor), 486, 488
FriendlyName, svojstvo (AppDoinain), 450
Extension, svojstvo FullName, svojstvo
(Directorylnfo), 316, 493
F (Filelnfo), 496
funkcije, 10
false, kljuna rije, 576 funkcije lanice, 10
FCL (Framework Class Library), 4
imenski prostori i, 12
klase Web Forms obrazaca, 358 G
Field, cilj atributa, 432
GAC (Global Assembly Cache), 425, 427
File, klasa, 492, 503 generalizacija, 99-101
metode, 496 generici, 6
OpenRead() i OpenWrite(), 503 klasa List
FileAttributes, klasa, 315
IComparable, iinplementiranje, 204-207
FileCopier, aplikacija (primjer), 310-334 IComparer, implementiranje, 207-212
implementira nje dogaaja gumba Copv, ogranienja upotrebe, 196-201
321- 324
suelje lEnumerable, 193-196
sortiranje popisa odabranih datoteka get, kljuna rije, 577
322- 324 get, pristupnik, 95
uzimanje odabranih datoteka, 321 get(), metoda i indekseri, 187-188
Delete, metoda za obradu dogaaja GetAttributes(), metoda (File), 496
324-334
GetCheckedFiles(), metoda, 321
osnovni obrazac korisnikog suelja, GetCreationTimesO, metoda
stvaranje, 312 (Directory), 492
TreeVie\v, obrada dogaaja, 317-320 (File), 496
TreeVierv, popunjavanje kontrole, 313-317 GetCurrentThreadlD(), metoda
Filelnfo, klasa, 503 (AppDomain), 450
CopyTo(), metoda, 500 GetData(), metoda (AppDomain), 450
metode i svojstva, 496-497 GetDirectories(), metoda
Filelnfo, objekti, 316 (Directory), 492
FileStream, klasa, 503 (DirectoryInfo), 314, 493
FileSystemlnfo, klasa, 492 GetEnumerator(), metoda
F ill(), metoda (DataAdapter), 342 (Dictionary), 218
FillDirectoryTree(), metoda, 313, 315 (lEnumerable), 194
FilterName, polje (Type), 443-444 (List), 202
Finalize(), metoda, 113 (Queue), 212
finally, iskaz, 253-255, 576 (Stack), 214
finalna klasa (Java), 112 (System.Array), 167
Fin d(), metoda (List), 202 GetFileList(), metoda, 321
FindAU(), metoda (List), 202 GetFilesO, metoda
FindMembers(), metoda (Type), 443 (Directory), 492
fixed, iskaz, 574
(Directorylnfo), 316, 493, 496
fixed, kljuna rije, 572
GetFileSystemlnfos(), metoda (DirectoryInfo)
float, tip podataka, 26, 577 493
Flush(), metoda (Stream), 503 GetHashCode(), metoda, 113, 218
for, petlje, 37, 48-50, 577
GetLastAccessTime(), metoda (File), 496
foreach, iskaz, 37, 50-52, 171-184, 441, 577 GetLastWriteTime(), metoda (File), 496
upotreba s lEnumerable, 195-196, 221 GetLength(), metoda (System.Array), 167
Form at(), metoda (String), 224 GetLocalDrives(), metoda
formateri, 449, 453, 470 (Directory), 492
podrazumijevani, 463 (Environment), 314
upotreba za serijaliziranje podataka, 537
K azala | 587
GetLowerBound(), metoda stvaranje tri GridVietv kontrole, 402
(System.Array), 167 tokovi podataka, itanje Web stranice kao,
GetMembers(), metoda (Type), 442 534
GetMethod(), 446 WSDL ugovor, pregled, 382
GetMethods(), metoda (Typc), 443 HTTP sesije, 359
GetO bjecr(), metoda (Activator), 445 HTTPChannel, tip, 463
GetO bjectData(), metoda (Dictionary), 218 HttpWebRequest, 534
GetParent(), metoda (Directory), 492 HttpWebResponse, objekt, 534
GetParentS'tring(), metoda, 32 0 -3 2 L
GetRange(), metoda (List), 202
GetResponse(), metoda, 534 I
GetResponseStream(), metoda I, operator (&&r), 57, 59
(NVebResponse), 534 IAsyncResult, suelje, 511
GetString(), metoda, 573 ICalc, suelje, 462
GetSubDirectoryNodes(), metoda, 315-316 ICloneable, suelje, 75
(Type), 445 ICloneable objekti, nizovi i, 221
GetType(), metoda, 113, 442 ICollection, suelje, 193
GetUpperBound(), metoda (System.Array), [Comparable, suelje, 193, 196-201
167 implementiranje, 204-207
.gif datoteke, 414 nizovi i, 221
Global Assembly Cache (GAC), 425, 427 IComparer, suelje, 193,322
globalne metode, 77 implementiranje, 207-212
gomila ogranienja, 212
alokacija elemenata polja, 168 lConvertible, klase, 222
definirana, 26 IDataReader, suelje, 338
goto, iskaz, 38, 45, 577 IDE (Integrated Development Enviroment), 16
iskaz switch, upotreba s, 42, 44 identifikatori, 35
grafiko korisniko suelje (GUI) definiranje, 60
alati za izradu, 12 ponitavanje definicije, 61
grananje, kljune rijei za IDeserializationCallback, suelje, 542
bezuvjetno grananje, 38 lDictionary, suelje, 193, 218
uvjetno grananje, 38 IDisposable, suelje, 82
GridLayout reim, dodavanje kontrola na Web IDL (Interface Definition Language), 7
Forms obrasce, 365 lEnumerable, suelje, 193-196, 214
GridViews, stvaranje, 402 nizovi i, 221
Group, klasa (Regex), 239-242 IEnumerator, suelje, 193, 214
GUI (grafiko korisniko suelje) alati za if, iskaz, 577
izradu, 12 ugnijeeni, 40-42
gumbi iskaz switch kao zamjena, 42
povezivanje podataka i, 367 if...else, iskaz, 38
IFormatter, suelje, 537
lLDasm, alat, 415
H ILI, operator (|), 59
Hejlsberg, Anders, 7 ILI, operator (j|), 57, 59
Hello World, program, 9-22 IList, suelje, 193
klase, objekti i tipovi, 9-15 imenovanje, naini, 15
prevoenje i pokretanje, 18-19 ,,deva i Pascalov zapis, 35
razvoj, 16 maarski zapis, 35
ureivanje, 16 imenski prostori, 12-13
uzorak koda, 9 ispisivanje cijelih, 15
HelpLink, svojstvo (Exception), 255 napomena za C++ programere, 12
HTML napomena za Java programere, 12
dodavanje Web Forms obrascima, 363 stvaranje u Visual Studiju .NET, 17
kontrole, dodavanje Web Forms obrascima, System.Text.RegularExpressions, 236
365 u primjerima koda, 29
posluiteljske kontrole, 367 XM L, za WSDL dokumente, 380
588 | Kazalo
IMessage, suelje, 483
nnplicit, operator, 577 IsBackground, svojstvo (Thread) 477
implicitno pretvaranje, 27 123 lsFixedSize, svojstvo (System.Array), 167
pakiranje, 115 iskazi, 37,60-63
in, iskaz, 37 bezuvjetno grananje, 38
in, operator, 577 bijeli prostor u, 36
inacica, broj za dijeljene sklopove 425 iteracija, 45-52
(pogledajte takoer sklopovi) continueibreak, 50-52
inaica, praenje, 414 do-while, petlja, 47
apstraktne klase u usporedbi sa sueljima, for, petlja, 48-50
foreach, 50
goto, 45
s pomou kljunih rijei new i override, 107
Increment(), metoda (Interlocked) 483 while, petlja, 46
indekser, deklariranje svojstva, 184 izrazi, 35
indekseri, 184-192 uvjetno grananje, 38
definirani, 184 if...else, 38
dodjeljivanje i, 188 svvitch, 42-45
get(), metoda i, 187-188 ugnijeeni if iskaz, 40-42
iskazi, blokovi, 40
preoptereivanje indeksera, 189-192
ser(), metoda i, 187-188 IsReadOnly, svojstvo (System.Array), 167
sintaksa, 187 s5ynchromzed, svojstvo (System.Array), 167
tliis, kljuna rije, 184 tem, element za klase kolekcije 202
IndexOf(), metoda Item, objekt, 397, 413
(List), 202 Item, svojstvo(IDictionary), 218
(String), 229 Item(), metoda
(System.Array), 167 (Dictionary), 217
inicijalizatori, 73-75 (List), 201
ImtializeO, metoda (System.Array), 167 ItemLookup, objekt, 397
lnnerException, svojstvo (Exception), 261 ItemLookupRequest, objekt, 397
JnputMream, klasa, metoda Readf) 503 ItemSearch, objekt, 413
lnsert(), metoda ItemSearchRequest, objekt, 413
(List), 202 ItemSearchResponse, objekt, 413
(String), 224, 229 Item_Bound, metoda (DataGrid), 407
(StringBuilder), 233 iteracija, iskazi za, 37 , 45-52
lnsertRange(), metoda (List), 202 continue i break, 50-52
instance, 9 do-while, petlja, 47
for, petlja, 48-50
brojanje s pomou statikih polja, 80
razlika izmeu klase i, 65 foreach, 50
instanceof (Java), 147 goto, 45
int, tip, 26, 578 while, petlja, 46
izdavai, 281
Intellisense, svojstvo Autocomplete 15
Interface, cilj atributa, 432 izlaz na zaslon, ispisivanje 28
interface, kljuna rije, 137 iznimke, 245-265
Interface Definition Language (1DL), 7 definirane, 245
Interlock, klasa, 480 Exception, objekti, 255-258
Interlocked, klasa, 482-483 izbacivanje i hvatanje, 246 -255
internal, kljuna rije, 107 catch, iskaz, 248-253
interna!, modifikator pristupa, 68, 577 finally, iskaz, 253-255
internal protected, kljuna rije, 107 throw, iskaz, 246-248
InternalErrorException, 261 metode za obradu iznimaka, definirane, 245
Internet, pozivanje Web usluga preko, 377 ponovno izbacivanje, 261-265
Internet Information Server(IlS) 450 prilagoene, 258-261
lnterruptf), metoda (Thread) 476 izolirano spremite, 5 44
IP adrese, 515 itanje iz, 545
is, operator, 147-150, 577 pisanje u, 545
u usporedbi s operatorom as, 151 izravan pristup memoriji, 8
izravna razmjena datoteka, 515
K azalo | 589
izrazi, 35, 48 definiranje, 65-70
Boolean, 38 argumenti metode, 68-70
regularni (pogledajte regularni izrazi) modifikatori pristupa, 67
uvjetni, 59 Time, klasa (primjer), 66
izvedene klase, 102, 113 definiranje tipova, 10
apstraktne klase kao osnovna klasa, 109 implementiranje vie suelja, 140, 157
premoivanje virtualne metode osnovne implemetiranje suelja, 153
klase, 108 instanca klase u usporedbi s, 65
izvoenje .NET lcomponenara, 564 ja v n e ,107
klasa Object kao korijenska klasa, 113
kolekcije unutar, pristup {pogledajte
J indekseri)
jaka imena za sklopove, 426 metode, 10
java, napomena za programere odnos izmeu, UML dijagrami, 100
decimalni tip, 25 pregled, 64
imenski prostori, 12 razlika izmeu struktura i, 129, 131
konstante lanice, 136 refleksija, 439
M ain(), metoda, 10 statike, 79
pravokutna polja, 174 stvaranje i imenovanje u Visual Studiju
referentni parametri, 85 .NET, 17
statike metode, pozivanje , 78 ugnjeivanje, 117
statiki konstruktori, 79 zapeaene,112
ugnijeene klase, 118 klijenti
zapeaena klasa, 112 mrenog toka podataka, stvaranje, 519
javna svojstva rad na daljinu, 469-470
AppDomain klase, 450 izgradnja, 465
Filelnfo klasa i, 496-497 za asinkrone mrene tokove, 521
javne statike metode, prekidanje dretvi, 476 klijentska podrka, .NET Web uslugama, 378
javni kljuevi, 426 klijentski aktivirani posluiteljski objekti, 461
oznake za, 428 klju i vrijednost, veze izmeu, 217-219
javni pristup, modifikator za, 68 ,107 , 578 referentni tip kao klju, 219
jedan modul, sklop s, 416 kljune rijei u C# , 575-580
jedan poziv, objekti s, 461 kod
jednakost, operator (==), 56 odvajanje korisnikog suelja od, 358
operator pridruivanja (=) u usporedbi s, 41 podruje, saimanje u Visual Studiju, 62
premoivanje, 122 ponovna upotreba, 102
jednostavni tipovi smjernice za stil (Microsoft), 15
popis, 25 kolekcije
JIT (Just In Time), prevoditelj, 6, 19 klasa List, 201-212
Jo in (), metoda implementiranje iComparable, 204-207
(String), 224 implementiranje lComparer, 207-212
(Thread), 490 klase, 166
klase vrlo tipiziranih, 24
MatchCollection, 238-239
K redovi, 212-214
kanali, 449, 453 rjenici, 217-219
registriranje na klijentu, 465 stogovi, 214-217
stvaranje, 463 suelja, 193-196
kasno povezivanje, 107, 445, 558 IComparable, 196-201
refleksija i, 562 lEnumerable, 193-196
KeepAlive, zastavica, 476 ureivanje Listltems, 365
Keys, svojstvo (Dictionary), 217 komentari, 11
KeywordRequest, objekt, 412 u stilu jezika C (/*... 7 ), 11
klasa, lanovi, 65 u vie redova, 11
lanovi instance ili statiki lanovi, 77 XM L, 334-336
klase za dokumentaciju, 334-336
apstraktne (pogledajte apstraktne klase)
C# , podrka za definiranje i rad s, 7
590 \ Kazalo
komponentno orijcntii ' i i no programiranje, 7
konstante, 31 L
enumeracije kao zamjena za, 3.3 LastAccessTime, svojstvo
enumerirane, 33 (Direaorylnfo), 493
inieijaliziranje, 32 (Filelnfo), 496
ponovno inieijaliziranje za vrijeme LascindexOf(), metoda
prevoenja, 32 (List), 202
n simboline, 31 (String), 224
konsrrukrorza kopiranje, 75 (System.Array), 167
konstruktori, 70-72 LastlVritelime, svojstvo
i deklariranje, 71 (Directorylnfo), 493
osnovne klase, pozivanje, 106 (Filelnfo), 497
podrazumijevani, 107 Length, polje
preoptereeni, definirani, 73 (String), 228
preoptereivanje, 90-93 (StringButlder), 233
statiki, 78 Length, svojstvo
strukture, 131 (Capture), 242
konteksti, 448, 459 (Filelnfo), 497
kontekstno povezani i okretni objekti, 459 (String), 228
rasporeivanje preko granica, 459 (Systeni.Arrny), 167, 169
kontekstno vezani objekti, 459 Listltem Collection Editor, 365
kontrole literati, 31
ActiveX literali (regularni izraz), 235
stvaranje, 549 literati niza, 222, 226
u .NET-u, 552 Directory info, objekt, stvaranje, 493
uvoenje, 548 oznaeni simbolom 239
aspdabel, kontrola, 402 Load, dogaaj, 360
$ dodavanje na Web Forms obrasce. 365-367 Load(), metoda
posluiteljske, 367 (AppDomain), 450
I (Assembly), 440
povezane s podacima, ADO.NET, 349-355
DataGri, programsko popunjavanje, LoadPostData(), metoda, 360
352-353 LoadViewSrate(), metoda, 360
podeavanje DataSet, 353-355 lock, iskaz, 577
povezivanje podataka s, 367-377 lock, kljuna rije, 484
TreeVie\v logiko ekskluzivno ILI, operator H , 59
obrada dogaaja, 317-320 logiko ILI (|), operator, 59
popunjavanje, 313-317 logiki operatori, 57
Web, 357 logiki vrijednosni tip, napomena za C i C++
posluiteljske, 363 programere, 25
uobiajene, 27 lokalne varijable, prikaz vrijednosti u programu
konzola za uklanjanje pogreaka, 21
aplikacije, 12 lokoti, sinkroniziranje dretvi, 480, 484-485
ispisivanje na long, tip, 26, 577
asinkroni posluitelj za mrene tokove
podataka, 521 M
klijent mrenog toka podataka, 519
korijenska klasa, 113 maarski zapis, 35
korisnika konfiguracija, informacije o, 544 M ain(), metoda, 10, 78
korisniki definirani tipovi, 23 asinkroni U/I i, 511
serijalizacija, 536 izgradnja posluitelja koji koristi, 462
korisniko suelje, 358 konzolne aplikacije i, 12
kraj reda (napomena za Visual Basic napomena za C++ programere, 10
programere), 37 napomena za Java programere, 11
kultura, 430 SingleCall, upotreba, 467
static kljuna rije i, 16
zavrne toke i, 469-470
K azalo | 591
makefile datoteka za sklop s vie modula, 418 statike, 15, 77
manifesti, 415 pozivanje, 77-78
dijeljeni sklop (primjer), 428 pristup statikim poljima, 81
sklopa svie modula (primjer), 421 suelja (p o g le d a jt e suelja)
manje ili jednako (<=), operator, 56 virtualne (p o g le d a jt e metode, polimorfne)
manje od, operator (<), 56 zadavanje tijekom izvedbe, 267-275
mape, 492 metode instance, delegati i, 276
Directorylnfo, objekt, stvaranje, 493-495 metode za obradu dogaaja, 359
rekurzija kroz.podmape, 493-495 definirane, 282
rad s, 492 Microsoft
rekurzija kroz podnrape, 315 naini imenovanja, 35
irenje, 318 smjernice za pisanje koda, 15
MarshaK ), metoda (RemotingServices), 467, Microsoft SQL Server Desktop Engine
469-470 (MSDE), 343
MarshalByRefObject, 454, 462 mjeavine, 137
Match, klasa, 238-239, 242 mnoenje ('), operator za, 52
kolekcije Grotips, 239 modifikatori pristupa, 67, 107
MatchCollection, klasa, 238-239 metode suelja i, 139
matematiki operatori, 52-54 statiki konstruktori i, 79
Matli klasa, C o s(), metoda, 445 svojstava, 96
meuspremnik, 503 modulo, operator (%), 52
privren u memoriji, 572 Module, cilj atributa, 432
MemberFilter, parametar, 443-444 moduli, 414
MemberTypes, parametar, 443-444 mogunosti, klase, 137
MemberwiseClone(), metoda, 113 Monitor, klasa, 480
memorija, izravan pristup s pomou monitori, sinkroniziranje dretvi, 485-489
pokazivaa, 8 Monitor, objekt (primjer), 486-489
MemoryStream, klasa, 503 Mono, prevoditelj, 19
Message, svojstvo (Exception), 255 Move(), metoda
MessageBox, statika Show() metoda, 324 (Directory), 492
(pogledajte takoer atributi; refleksija) (File), 496
metapodaci, 7, 414 MoveFile(), metoda, 568
datoteke Assemblylnfo.cs, 418 MoveFirst(), metoda, 338
definirani, 431 MoveTo(), metoda
refleksija i, 438 (Directorylnfo), 493
metaznakovi (regularni izraz), 235 (Filelnfo), 497
Method, cilj atributa, 432 P/lnvoke i, 568
Methodlnfo, objekt, 446 mscorlib, sklop, 415
metode MSDE (Microsoft SQL Server Desktop Engine),
anonimne, 294 343
apstraktne, 109 MS1L (Microsoft lntermediate Language)
primjer, 109-110 datoteke
argumenti, 68-70 JIT prevoenje i, 19
definirane, 10 prevoenje i, 6
definiranje i deklariranje, 67 M u lt(), metoda, 379
deklariranje, 11
klase u usporedbi s globalnim, 77
klase Appdomain, 450 N
klase Object, 113 Name, svojstvo
modifikatori pristupa, 67 (DirectoryInfo), 316, 493
neizravno pozivanje, 7 (Filelnfo), 316, 497
polimorfne, 103 namespace, kljuna rije, 578
povratni pozivi, 299-302 namijenjena samo itanju, polja, 97
pozivanje s pomou operatora . (toka), 12 nasljeivanje, 102-119
preoptereivanje, 90-93 implementiranje, 102
rasporeivanje, zadavanje, 454 klasa C# , 7
592 | Kazalo
napomena za C i C++ programere, J 13 pronalaenje podnizova, 229-231
od klase Object, 113 prvoklasni tip u C# , 220
regularnih izraza, 242 rad sa, 223-229
sprjeavanje s pomou zapeaenih klasa, kopiranje nizova, 227
J 12 metode i polja klase String, 223
nasumini brojevi, 219 nastavljanje nizova, 227
navodni znaci u nizovima, 399 provjere jednakosti, 227
navodnici, nizovi pod, 222 traenje podniza, 229
NE, operator (!), 57
umetanje podniza, 229
neinicijalizirane varijable, 31 usporedba nizova, 226
neizravno pozivanje metoda, 7 stvaranje, 222
nejednaka polja, 177-179 koristei ToString(), 223
nejednakost, operator za (!=), 56 umake, program, 419
nepovezani podaci, arhitektura, 337 Nodes, svojstvo (TreeVietv), 314
nepovratni dogaaji, 359 NonSerialize, atribut, 542
.NET
normalizacija, 339
izvoz komponenata Notepad
biblioteka tipova, stvaranje, 567 ureivanje programa s, 16
komponente, izvoenje, 564 Web obrasci, stvaranje, 358
kontrole! uvoenje, 552 nuli, referenca, 578
P/Invoke (usluga za pozivanje platforme), NullReferenceException, 261
567
programiranje, 548-574
sigurno pisanje koda, informacije o, 371
uvoenje COM DLL-a u, 558 Object, klasa, 113
biblioteka tipova, 558 metode, 113
kasno povezivanje i refleksija, upotreba, nasljeivanje od, 113
562 Object, parametri, 444
probni program, stvaranje, 559 object, tip, 578
.NET kostur, 4-5 objekti
arhitektura, 5 ADO.NET (pogledajte ADO.NET, objektni
klase za U/l, 503 model)
tokovi podataka i, 491 definirani, 10
.NET platforma, 3 indenttfikatori, 452
.NET Web usluge, 357, 377 iznimaka, 255-258
izgradnja kao referentni i vrijednosni tipovi, 132
kalkulatora (primjer), 380 klasa Object kao korijen svih klasa, 112
pregledavanje WSDL saetka, 382 kontekstno povezani i okretni, 459
izrada Web usluge, 378-383 na stogu i gomili, 26
klijentska podrka, 378 proirenje u razvojnom okoliu programa za
posrednik, stvaranje, 383-388 pronalaenje pogreaka, 21
testiranje usluge, 386 rad na daljinu, 461
testiranje, 381 tipovi posluiteljskih objekata, 461
NetvvorkStream, klasa, 503, 517, 519 rasporeivanje (pogledajte rasporeivanje)
new, kljuna rije, 70, 578 serijalizacija (pogledajte serijalizacija)
instanciranje polja, 168 sinkronizacija, 460
praenje inaica s pomou, 107 sinkronizacija dretvi i, 480
stvaranje struktura, 132 stvaranje, 70-75
stvaranje struktura bez upotrebe, 133-135 inicijalizatori, 73-75
niz, literali, 226 kljuna rije this, 75
niz znakova za povezivanje, 396 konstruktori, 70-72
nizovi, 35, 221-234 suelja lCloneable, 75
definirani, 12 stvaranje s pomou metoda klase Activator,
dijeljenje, 231-233 445
dinamiki, 233-234 tokovi s meuspremnicima, 505
ogranienja graninika, 234 unitavanje, 81-84
primjena regularnih izraza na (pogledajte C# destruktori, 81
regularni izrazi) Close(), 83
Kazalo | 5 93
destruktori u usporedbi s metodom pridruivanje (=), 52
dispose, 82 smanjenje i poveanje, 54
iskaz tising, 83 ternarni (?:), 59
objektno orijentirano programiranje osnovne klase, 102
napomena za VB6 programere, 99 apstraktne klase kao, 109
klasa Object kao korijen svih klasa, 112
stvaranje novih tipova, 9
konstruktori, pozivanje, 106
ObjRef, objekt, 469-470
obrada poslanih podataka, 360 virtualne metode, premoivanje, 103
Observer (Pubiish/Subscribe), predloak, 282 osnovni tip (pozadinski tip) za eiuimeracije, 33
ostatak pri dijeljenju, 52
OCX standard, 548
odmotnvanje stoga poziva, 250 otkrivanje (tipova), 439-440
out, modifikator, 578
odnos, operatori, 56 out, parametar, 84, 87
oduzimanje (-), operator za, 52
override, kljuna rije, 103,578
odvajanje stanja klase i metode, 93
praenje inaica s pomou, 107
odvodi, 453
oznaka javnog kljua, 428
definirani, 449 oznake, 45
rasporeivanje s posrednicima, 453
stvaranje lanca posluiteljskih odvoda, 463 aspabel kontrole, 402
ogranienja, 212
veza izmeu razliitih tablica u bazama P
podataka, 339
P/Invoke (usluga za pozivanje platforme), 567
okretni objekti, 459 pozivanje Win32 API metode, 568
OLE DB upravljani izvor podataka, 346-348 padajui popisi, 66
OnDeserialization(), metoda, 542
PadLeftO, metoda (String), 224
O nLoadl), metoda, 360 PadRighc(), metoda (String), 224
OnPreRenderO, metoda, 361
OnReadComplete(), metoda, 521 pageLayout, svojstvo, 365
pakiranje tipova, 25 ,115
OnRotvDataBound, dogaaj, 402
reference suelja, 160, 163
OnWriteComplete(), metoda, 521
strukture, 132
O pen(), metoda (Filelnfo), 497
Parameter, cilj atributa, 432
OpenReadf), metoda parametri, 68
(File), 496, 503
prosljeivanje, 84-90
(Filelnfo), 497 po referenci, 85-87
otvaranje binarnih datoteka, 503
s definitivnim pridruivanjem, 87-90
OpenText(), metoda (Filelnfo), 497
OpenWrite(), metoda vraanje vrijednosti, 85
params, kljuna rije, 172-173, 187
(File), 496 upotreba sa Splir() metodom (String), 232
otvaranje binarnih datoteka, 503
(Filelnfo), 497 params, modifikator parametra, 578
Patent, svojstvo (Directorylnfo), 493
operator, kljuna rije, 118, 578
Pascalov zapis, 15, 35
operator pridruivanja (=), 52
PE (Portable Executable) datoteke, 414
operator jednakosti (==) u usporedbi s, 41
operator za pretvaranje tipova, mijenjanje Peek(), metoda
(Queue), 212
tipova s pomou, 28 (Stack), 215
operatori, 52-60
Perl 5 regexp, 236
logiki, 56
petlja, iskaz za stavljanje u, 37
matematiki, 52-54 petlja, varijable za stvaranje, napomena za VB6
odnosni, 56 programere, 49
operator as, 150-151
pisanje izlaza na zaslon, 28
operator is, 147-150
plitka kopija, 75
pokazivai, 570 podaci
prednost, 57-59
itanje i upisivanje, 502-509
preoptereivanje, 120-128
privremeni, obrada, 541
jednakost (==), operatora, 122
podmape
logiki parovi, 122
operator, upotreba kljune rijei, 120 rad sa, primjer, 500-502
rekurzija kroz, 315, 493-495
operatora za pretvaranje, 123-128
zahtijevanje popisa od trenutne podmape, 493
stvaranje korisnih operatora, 121
594 | K azalo
podnizovi, smjetanje unutar nizova, 229 zadavanje preko suelja, 461
podrka na strani posluitelja za .NET Web posluiteljske kontrole, 363
usluge, 378
dodavanje Weh Forms obrascima, 365
pogreke, definirane, 245
tipovi u Web Forms obrascima, 367
Point, klasa, 455
pokaziva, tipovi, 24 posluiiteljski objekti koji podravaju rad na
daljinu, 461
pokazivai, 8, 570
posrednici, 378
referenca this u usporedbi s, 75
klasa posrednika za klijenta Web usluga
upotreba u C# programu (primjer), 573-574 391
polimorfizam, 102-109
definicija, 99 rasporeivanje preko granica konteksta, 459
rasporeivanje s, 453
metoda Equals(), premoivanje, 122 stvaranje, 383-388
praenje inaica s pomou kljune rijei testiranje Web usluge, 386
ovem'de, 107 posrfix, operatori, 55
stvaranje polimorfnih metoda, 103 potpis metode, 90
stvaranje polimorfnih tipova, 103 potpisi (digitalni), 426
polja, 166-184
deklariranje, 168 potpisivanje sklopa, 426
poveanje i smanjenje, operatori za, 55-56
granice, 179
povezivanje, 452
inicijaliiranje elemenata, 172
kasno (pogledajte kasno povezivanje)
iteriranje krozs pomou iskaza foreach, 171 uvoenje COM DLL-a u .NET, 558
konverzija, 180-182
List klasa, 201-212 povezivanje podataka, 367-377
konfiguracija izvora podataka, 368
metoda Sorr(), 182-184
kontrole i dogaaji, dodavanje Web Forms
namijenjena samo itanju, 97
objekata, 103 obrascima, 372-377
odabir izvora podataka, 368
podrazumijevane vrijednosti, 169 pozivanje polja s kontrolom radio-gumba
primjer, 169
(primjer), 371
pristup lanovima s pomou operatora testiranje upita, 370
indeksa, 103 povratni dogaaji, 359
pristup elementima, 169 Pow(), metoda, 379, 387
sortiranje, 182-184
pozadinske dretve, 477
primjer, 205-207, 208-212
pozadinski kod, datoteke, 358,362-364
statika, 80
veliina, 201 prikaz izlaza za klijenta Web usluge
(primjer), 404-406
viedimenzionalna, 174-179 razlike u odnosu na ASP.NET 1.x, 362
inicijaliiranje dvodimenzionalnih, 175-176 pozadinski kod, stranice s, 356
pravokutna, 174-177
pozicijski parametri, za konstruiranje atributa
zupasta, 177-179 434
ponovno izbacivanje iznimaka, 261-265 RegisterWellKnownServiceType(),
Pop(), metoda (Stack), 215 pravokutna polja, 174-177
popisi
pranjenje meuspremnika, 505
List, klasa, 201-212 preaci na tipkovnici, 18
implementiranje IComparable, 204-207 predloci, C++, 6
implementiranje IComparer, 207-212 predmemorija, 491
metode i svojstva, 201-202 prednost operatora, 57-59
svojstvo Capacity, 204
pretprocesorske direktive
sortiranje popisa odabranih datoteka # define iskaz, 60
(primjer), 322-324 # elif, # else i # endif, 62
Portable Executable (PE) datoteke, 414 # region, 62
poslani podaci, obrada, 360 # undef, 61
posluitelj, kontrole (ASP.NET), 367 pretprocesor, napomena za C i C++
posluitelji
programere, 61
asinkroni posluitelj mrenog toka prefiks operatori, 54
podataka, 521 preglednici
izgradnja, 463 IP adrese i, 515
posluitelj mrenog toka podataka, Web Forms obrasci pokrenuti na, 358
stvaranje, 516
preimenovanje datoteka, 500
K azalo | 595
SingleCall objekt, upotreba, 467
prekidanje dretvi, 476-479
tipovi posluiteljskib objekata, 461
premoivanje zadavanje posluitelja s pomou suelja,
implementacije suelja, 153-156
metode klase Object, 115 462
zavrne toke, 469-470
preoptereeni konstruktor, definiran, 73
RaisePostDataChangedEvent(), metoda, 360
preoptereivanje
Rank, svojstvo (System.Array), 167
metoda i konstruktora, 90-93
rano povezivanje
operatora, 120-128
koji podravaju druge .NET jezike, 121 definirano, 558
Rapid Application Development (RAD), 6
pretprocesorski iskazi, 60-63
raspakiranje, tipovi za, 115
pretplatnici, 281 rasporeivanje, 448
pretraivanje prema kategoriji, Web usluge, 408
definirano, 448
pretvaranje tipova, 27
objekta bez poznate zavrne toke, 469-470
pretvaranje ugraenih tipova, 27 po vrijednosti, 448, 453
pretvaranje, operatori za, 123-128
po vrijednosti ili po referenci, 453
prevoditelj u odzivniku, 19
preko granica aplikacijske domene, 454
prevoenje
primjer, 455-458
MSIL datoteke i, 6
s posrednicima, 453
normalizacija i, 339 preko granica konteksta, 459
pokretanje programa Hello World, 18
razlikovanje velikih i malih slova, 15
privrivanje meuspremnitta, 572
ientifikatori, 35
prijateljsko ime, 451 usporedbe nizova, 226
prilagoene iznimke, 258-261
usporedbe nizova unutar DacaTable
prilagoeni atributi, 433
objekata, 353
primjer, 435 RCW (Runtime Class Wrapper), 558
primarni kljuevi, 338 (lnputStream), 503
podrazumijevane vrijednosti, 70-71
(Stream), 503
serijalizacija, 536
Read(), metoda, 573
PrintValues(), metoda, 214
ReadFile(), metoda, 571
pristup lanovima (->), operator za, 570
ReadLine(), metoda (klasa StreamReader i
private, kljuna rije, 107 StreamWriter), 507
private, modifikatori, 578
readonly, modifikator polja, 578
privatni kljuevi, 426 RealProxy, klasa, 453
privatni sklopovi, 424
redovi, 212-214
privremeni podaci, 542
primjer, 213-214
proceduralni jezici, 339
Queue klasa, metode i svojstva, 212
procesi ref, modifikator, 578
aplikacijske domene za, 450
ref, parametri, 84, 87
definirani, 448 reference na vrijednosne tipove, 160-165
ProcessExit, dogaaj, 450
ReferenceEquals(), metoda, 113
ProgCS, imenski prostor, 418 referentni parametri, 85
programiranje temeljeno na dogaajima, 266
propadanje do sljedeeg iskaza case, 44 referentni tipovi, 24
alokacija na gomilu, 26
Property, cilj atributa, 432
prosljeivanje parametara prema referenci, 85-87 klase kao, 129
objekti kao, 132
proirenje osnovnih klasa kostura, 6
odnosi izmeu kljua i vrijednosti i, 219
proirenje suelja, 140
Publish/Subscribe (Observer), predloak, 282 pakiranje i raspakiravanje, 115
Pulsef), metoda (Monitor), 485, 488 polja, 169
polja kao, 168
Push(), metoda (Stack), 215
refleksija, 438
definirana, 431
R kasno povezivanje i, 445, 562
rad na daljinu, 460 otkrivanje tipa, 440
izgradnja klijenta, 465 pregledavanje metapodaraka, 439
izgradnja posluitelja, 463 tipa, 442
RegisterWellKnownServiceType(), metoda, Refresh(), metoda (Directorylnfo), 493
596 ( Kazalo
Regex, klasa, 235-237
Split(), metoda, 237 Select Case, iskaz (VB6), 44
Serializable, atribut, 454, 461
RegistetChanneK), metoda (ChannelServices) Seria!ize(), metoda, 537
463
serijalizacija, 454, 536
RegisterWellKnovvnServiceType() metoda descrijalizacija objekta, 538
463, 467
regularni izrazi, 220, 235-237 formateri, upotreba, 537
temeljeni na Perl 5 regexp, 236 objekti, stvaranje tokova podataka, 491
obrada privremenih podataka, 542
CaptureCollection, koristei, 242-244
definirani, 235 rad s neserijaliziranim objektom, 542
rasporeivanje i, 537
literali i metaznakovi, 235
serijaliziranje i deserijaliziranje objekta
MatchCollection i Match klase, 238-239
(primjer), 538
nasljeivanje, 242
serijaliziranje objekta, 538
Regex klasa, upotrebom, 235-237
upotreba, 537
rekurzija kroz podmape, 493
relacijske baze podataka, 337-341 Service Oriented Architecture Protocol
definirane, 337 (,pogledajte SOAP)
sesije, HTTP, 359
normalizacija, 339
SQL, 339 set, pristupnik, 96, 579
tablice, zapisi i stupci, 338 se t(), metoda i indekseri, 187-188
Relations, svojstvo (DataSet), 342 SetAppDomainPo!icy(), metoda, 450
SetAttributes(), metoda (File), 496
RemotingConfiguration, klasa, 463
SetCheckO, metoda, 320
RemotingServices, klasa, MarshaK), metoda
467, 469-470 SetCreationTime(), metoda (File), 496
Remove(), metoda SetData(), metoda (AppDomain), 450
(Dictionary), 218 SetLastAccessTime(), metoda (File), 496
(List), 202 SetLastError, parametar, 568
(String), 224 SetLastWriteTime(), metoda
(File), 496
(StringBuilder), 233
RemoveAt(), metoda (List), 202 SetValue(), metoda (System,Array), 167
Shape, klasa, 451, 453
RemoveRange(), metoda (List), 202
Shared Source CL1 prevoditelj, 19
Rep!ace(), metoda (StringBuilder), 233 short, tip, 26, 579
ResourceResolve, dogaaj, 450 Show(), metoda, 313
resursi, simuliranje dijeljenih, 480
return, iskaz, 38, 578 (MessageBox), 324
ShowModal(), metoda, 313
ReturnValue, cilj atributa, 432
Reverse(), metoda, 182-184 sigurne za tipove, kolekcije (pogledajte generici)
(List), 202 sigurnosne granice, 415
sigurnost
(System.Array), 167, 182-184
rjenici, 217-219 aplikacijske domene i, 451
suelje IDictionary, 218 parametarizirani upiti, upotreba, 399
Root, svojstvo (DirectoryInfo), 493 sigurno pisanje koda u.NET-u, 371
simbolike konstante, 31
Rows, kolekcija (DataTable), 342
R u n(), metoda, 521 Simple Object Access Protocol (pogledajte
SOAP)
asinkroni U/l i, 511
SingleCall, objekti, 467
runat=server, atribut, 363
Singleton, objekti, 467
Runtime Class Wrapper (RCW), 558
sinkronizacija, 461, 480-489
Interlocked, upotreba klase, 482-484
s lokoti, upotreba, 484-485
sadrana klasa, 118 monitori, upotreba, 485-489
sakriveni bitovi, 315 stanje natjecanja, 489-490
sakriveni lanovi suelja, 159 zastoj, 489-490
598 | K a z a lo
definiranje, 137
eksplicitna implementacija, 1 5 6 - 1 6 5
metode, selektivno izlaganje 1 5 9 tablice baza podataka, 338
Pi'istup zapeaenim klasama i ogranienja veza izmeu, 339
vrijednosnim tipovima, 160-16.5
sakrivanje lanova, 159 TCM P 1! 1 bijeli prostor)
implementiranjc (jednostavan primjer) T r / P kiHla b" 1'lm i formi ter, 45.3
138-139 rCP/lP veze, 515
tokovi podataka, stvaranje, 519
implemenr/ranje vie, 140 IcpC/ient, klasa, 519
instanciju nje, direktno, 1 4 6 TcpLisrener, objekt, 516
izgradnja posluitelja kroz, 462
tehnologije ifriranja za jaka imena, 426
kolekcija (pogledajte kolekcije, suelja) tekstualne datoteke, rad s, 507
kombiniranje, 141
tekstualno itanje (datoteke), 503
metode, pristup, 145-1.52
ternarni operator (?:), 5 9 , 320
operator as, 150-151 Test.cs datoteka, 421
operator is, 147-150 7extReaer, klasa, 503
pretvaranje u suelje, 146 TextWriter, klasa, 503
modifikatori pristupa i, 96 tfiis, kljuna rije, 75, 5 7 9
piemosctvanje implementacija, 1 5 3 - 1 5 6 indekseri i, 184
produivale i kombiniranje (primjer), Thread, klasa, 472
Abort(), metoda, 476
proirivanje, 140
InterruptO, metoda, 476
stvaranje instance, 146
Sleep(), metoda, 475-476
svrha, 137
T iteadAbortException, iznimka, 476
zadavanje posluitelja preko, 461 I hreadSrart, klasa, 472
svi ciljevi atributa, 432
thrmv, iskaz, 38, 246-248, 264 579
svojstva, 93-96 tijek programa,3 7
definiranje u C# klasi, 10 Time, primjer klase, 6 6
deklariranje, 95 tip, otkrivanje, 440
delegati kao, 277
tip povratne vrijednost, odreen u deklaraciji
modifikatori pristupa, 96
metode, 11 J
oprez pri upotrebi, 135 tipovi, 9, 23-28
polja, 169
biblioteke, 558
prisrupnik get, 95
enumeracije, 33-35
pristupnik set, 96
pakiranje i raspakiravanje, 115
refleksija i, 438
upotreba (primjer), 9 3 (p ^ da/te ugraeni tipovi)
tipovi, biblio teka, 567
svvitch, iskaz, 42-45, 5 7 9
Tlblmp.exe, uvoenje biblioteke tipova 558
SyncRoot, svojstvo (System.Array), 1 6 7 ToArray(), metoda
oystem, imenski prostor, 12 (List), 202
upotreba kljune rijei i, 13 (Queue), 212
System.Array, klasa, 182-184 (Stack), 215
metode i svojstva, 167 toke prekida
ToStringO, metoda, 182 postavljanje, 20
System.HnterpriseServices.Synchronization, T pokretanje programa, 20
atribut klase, 460 loCharArray(), metoda (String) 224
System.Exception, objekti, 2 5 5 , 2 6 4 tokovi podataka, 491-547
System.Int32, klasa, 204
asinkroni U/I, 510-514
System.Reflectton, imenski prostor, 4 3 3 4 3 9 binarne datoteke, itanje, 503-505
System.String, klasa, 2 2 0
deklaracija, 221
itanje 1 upisivanje podataka, 502
definirani, 491
System.Text.RegularExpressions, imenski izolirano spremite, 544
prostor, 236 itanje iz, 5 4 5
System.Text.StringBuiJder, klasa, 233 pisanje u, 545
5ystem.Threadtng, imenski prostor, 4 7 1 klase .NET kostura, 503
5ystem.Web, imenski prostor, 356, 358 krajnje toke, 491
System.Web Services, imenski prostor, 378 s meuspremnicima, 505
System.Web.UI, imenski prostor, 356, 358 serijalizacija objekata, 536
Kazalo / 599
postavljanje toaka prekida, 20
deserijalizacija objekta, 538 klijent m renog toka podataka, stvaranje,
fornvateri, upotreba, 53/
519 , ,
obrada privremenih podataka, poslu itelj m renog toka po data ka,
spriializaciia objekta, j j o , . . . stvaranje, 516
serijalizacija/deserijalizacija (primjer), viestruke veze, obrada, 521
( p o g le d a jt e t a k o e r tokovi)
tekstua5l3n8e datoteke, wd. sa, 5= 0A77 ulaz/izlaz (U/l)
klijent mrenog toka p odat, , ,
asinkroni, 4 9 2 , 510 , 516
stvaranje, 519 glavne klase .N ET kostura za, 503
posluitelj za mreni tok podata . ,
stvaranje, 516 ^ t e S i z l a z a , klijent W eb usluga, 399
viestruke veze, obrada, 52 datoteka s pozadinskim kodom,
ulaz i izlaz preko mree, 514 4 0 4 -4 0 6
standardni izlaz, 12
W 1 u 2 t w e b stranica kao HTML tokova
ulazi, 515 . ric
podataka, 534 ulazi (identifikatori aplikacije), 513
tokovi s m eusprem nicim a, 505 ulaz i izlaz preko m ree, 514 _
ToLower(), metoda (Stnng), 22 UM L (Unified M odeling Language), 100
(System.Array), 182 unchecked, operator, 579
T o Strin g (), metoda, 113, 223
T o U pper(), metoda (Stnng), 22 Unified M odeling Language (pogledajte U M U
TP (transparentni posrednik), Uiiiforin Resource Identifier (U R I), 534
TreeNodeCollection, objekt, unikatni objekti, 461
TteeVietv, kontrole (P "m j ) U n load (), m etoda (AppDom ain), 4 50
obrada dogaaja, 317-320 unsafe, kljuna rije, 572
popunjavanje, 313-317 unsafe, m odifikator, 5 7 1 ,5 7 9
T rim (), metoda (Stnng), unutarnje iznim ke, ponovno izbacivanje
TrimHndO, metoda ( S m n g ) ,^ (prim jer), 261-265
T rim S ta rt(), metoda (Stnng)- 22 unutarnji podaci, 21
T rim To Size(), metoda (List), 202 unutarnji spoj (S Q U , 340
true, kljuna rije, 579 U nw rap(), m etoda (ObjectH andle), 452
try iskaz/blok, 2 4 8 ,5 7 9 upiti, 3 4 0 _ ,
Type, klasa param etatizirani radi sigurnosti, 399
FilterName, polja, 443-444
FindMembers(), mecoda 4 upravljani izvori za A D O .N ET, 3 4 6 -34 8
GetMembers( ) , mecoda 442
GetMethodsO, metoda 442 jjr j(U nifo^m Ilesourc e ld em?fier), 4 6 5 ,5 3 4
GecType(), metoda 445 ushort, tip, 5 8 0 , 1Q
typeof, operator, 439, 4 6 3 , 579 using, direktiva (u prim jerim a koda), 2y
using, iskaz, 14, 83 , 5 80
atributi sklopa nakon, 433
usklaivanje uzoraka (.p og led ajte regularni
uahurivanje podataka sa svojstvima, 93-96 izrazi)
udaljeni objekti, z?P'S'va"Je u 51 uvjetno 1, operator (& & ), 59
ugnijeeni iskaz u, 40- uvjetno ILI, operator (II), 59
iskaz switch kao zamjena, 42
uvjetni izrazi, 59
ugnjeivanje napom ena za C i C++ program ere, 38
iznim aka, 261 uvjetni operator (?), 320
klasa, 118 uvjetno grananje, 37, 38
kom entara, 12 if...else iskaz, 38
ugraeni tipovi, 24-28 switch iskaz, 42 -45
char, 27 ugnijeeni if iskaz, 4 0 -4 2
odabir, 26 uvoenje
ugraeni tipovi, 25 COM kom ponenata, 5 56
uint, tip ,5 7 9 71-22 biblioteka tipova u .N ET, 558
uklanjanje pogreaka, Pr S r 2* C O M D LL-a u .N ET, 558
pokretanje programa bez uklanjanja
nosreaka, 18
600 | K a z a lo
kasno povezivanje i refleksija, 562 void, kljuna rije, U , 580
testni program, stvaranje, 559 volatile, kljuna rije, 580
kontrole u .NET, 552 vrijednosni parametri, 87
biblioteka tipova, stvaranje, 567 vrijednosni tipovi, 23
alokacija na stogu, 26
neinijalizirani, 72
V objekti kao, 132
valne, kljuna rije, 580 pakiranje i raspakiravanje, 115
Values, svojstvo (Dictionary), 217 polja, 169
vanjska klasa, 117 pristup, 160-165
vanjski kljuevi, 338 prosljeivanje u metode, 88
vanjski spoj (SQL), 340 strukture kao, 129, 132
varijable, 28-31 ugraeni, popis, 25
definirane, 28 vrijednosti, vraanje u parametrima, 85
inicijaliziranje i pridruivanje vrijednosti, vrlo tipizirani jezici, 23
29
konstante i, 31
napomena za VB6 programere, 29 w
neinicijalizirane, 30 W ait(), metoda (Monitor), 485, 490
pridruivanje bez inijaliziranja, 31 \Veb aplikacije
VB napomena za programere, kraj reda, 37 dogaaji, 359
VB6 CDbl, funkcija, 551 metode brzog razvoja primijenjene na, 356
VB6 napomena za programere prednosti, 306, 356
vee ili jednako(>=), operator, 56 stanje, 359
vee od(>), operator, 56 Web tokovi podataka, 533
veliina polja, 201 Web Forms obrasci, 6
veze (viestruke), obrada od strane mrenog dodavanje kontrola na, 365-367
posluitelja za tokove podataka, 521 posluiteljskih, 367
vidljivost klase i njenih lanova (pogledajte povezivanje podataka s kontrolama,
modifikatori pristupa) 367-377
VievvState, svojstvo, 360 pregled, 357-361
virtual, kljuna rije, 103, 580 dogaaji, 358
virtualne metode, 103 podjela korisnikog suelja, 358
klase Object, 113 ivotni ciklus, 360
premoivanje, 103, 107 stvaranje, 361-364
virtualni stroj, .NET CLR-a, 5 datoteke s kodom, 362-364
vie modula, sklopovi s, 416 (pogledajte takoer ASP kontrole)
izgradnja, 416 Web kontrole, 367
' ispitivanje, 421 Web Service Description Language (pogledajte
makefile datoteka, upotreba, 418 WSDL)
uitavanje sklopa, 422 Web usluge, 5
viedimenzionalna polja, 174-179 izgradnja .NET usluge
granice dimenzija, 179 kalkulator (primjer), 380
vieodredisni delegati, dohvat vrijednosti iz, pregledavanje WSDL saetka, 382
295-302 testiranje, 381
Visual Studio .NET izrada .NET usluga, 378-383
imenski prostor, stvaranje, 17 klijentska aplikacija (primjer), 389
kontrole ActiveX, uvoenje, 548, 552 izrada klijenta, 389
prednosti za razvoj softvera, 16 pretraivanje prema kategoriji, 408
programi za uklanjanje pogreaka, prikaz izlaza, 399
upotreba, 21-22 posrednik, stvaranje, 383-388
stvaranje konzolnih aplikacija, 17-18 testiranje usluge, 386
uvoenje ActiveX kontrole u, 552 Web.config, datoteka, 364
Web Forms obrasci, stvaranje, 358 WebRequest, objekt, 534
Visual Studio .NET Designer WebRequestFactory, klasa, 534
alatni okvir, 307 WebResponse, objekt, 534
izrada Windo-w Forms obrazaca, 306-310 GetResponseStrearo(), metoda, 534
prozor Properties, 308
K a z a lo | 601
\vhile, iskaz, 37 ugovor, pregled, 382
while, petlja, 46 , 580 X M L imenski prostor za W SD L dokum ente,
W iltam uth, Scott, 7 380
602 | K a z a lo