Commit beb7d8979578eb9046ef901dd389f2d0a998dd4b

  • avatar
  • Ville Tirronen <aleator @gm…l.com> (Committer)
  • Thu May 22 13:52:08 EEST 2014
  • avatar
  • Ville Tirronen <aleator @gm…l.com> (Author)
  • Thu May 22 13:52:08 EEST 2014
Lisätty ohj1. luentomonisteen raaka markdown versio
converters/Cleanup.hs
(31 / 0)
  
1{-#LANGUAGE OverloadedStrings, FlexibleInstances, FlexibleContexts, ViewPatterns#-}
2module Main where
3import Text.Pandoc.Walk
4import Text.Pandoc.Shared
5import Text.Pandoc.JSON
6import Data.List
7import Data.List.Split
8import Data.Char (isSpace)
9import qualified Text.Blaze.Html5.Attributes as A
10import Text.Pandoc.Shared
11import Text.Blaze.Html.Renderer.String
12import Data.Monoid
13import Data.Maybe
14import Control.Applicative
15
16main = toJSONFilter (\x -> walk remLinks $ walk joinImgs (x::Pandoc))
17
18
19toString :: [Inline] -> String
20toString = stringify . Plain
21
22remLinks :: Inline -> Inline
23remLinks (Link (toString -> "#") _) = Space
24remLinks (Link (toString -> "") _) = Space
25remLinks x = x
26
27joinImgs :: Block -> Block
28
29joinImgs (Para ((Image d t):des@((dropWhile isSpace . stringify) -> k)))
30 | "Kuva " `isPrefixOf` k = Para [Image des t]
31joinImgs x = x
data/ohjelmointi1/raw_lecture_notes.markdown
(10193 / 0)
  
1
2Esipuhe
3=======
4
5Tämä moniste on luentomoniste kurssille Ohjelmointi 1. Luentomoniste
6tarkoittaa sitä, että sen ei ole tarkoitus korvata kunnon kirjaa, vaan
7esittää asiat samassa järjestyksessä ja samassa valossa kuin ne
8esitetään luennolla. Jotta moniste ei paisuisi kohtuuttomasti, ei
9asioita käsitellä missään nimessä täydellisesti. Siksi opiskelun tueksi
10tarvitaan jokin hyvä aihetta käsittelevä kirja, sekä rutkasti
11ennakkoluulotonta asennetta ottaa asioista selvää. Tuorein tieto löytyy
12tietenkin netistä. On myös huomattava, että useimmat saatavilla olevat
13kirjat keskittyvät hyvin paljon tiettyyn ohjelmointikieleen—erityisesti
14aloittelijoille tarkoitetut. Osin tämä on luonnollista, koska ihmisetkin
15tarvitsevat jonkin yhteisen kielen kommunikoidakseen toisen kanssa.
16Siksi ohjelmoinnin aloittaminen ilman, että ensin opetellaan jonkun
17kielen perusteet, on aika haastavaa.
18
19Jäsentämisen selkeyden takia kirjoissa käsitellään yleensä yksi aihe
20perusteellisesti alusta loppuun. Aloittaessaan puhumaan lapsi ei
21kuitenkaan ole kykeneväinen omaksumaan kaikkea tietyn lauserakenteen
22kieliopista. Vastaavasti ohjelmoinnin alkeita kahlattaessa
23vastaanottokyky ei vielä riitä kaikkien kikkojen käsittämiseen. Tässä
24monisteessa ja luennolla asioiden käsittelyjärjestys on sellainen, että
25asioista annetaan ensin esimerkkejä tai johdatellaan niiden tarpeeseen,
26ja sitten jonkin verran selitetään mistä oli kyse. Tästä syystä tästä
27monisteesta saa yhden näkemyksen mukaisen pintaraapaisun asioille ja
28kirjoista ja nettilähteistä asiaa on syvennettävä.
29
30Tässä monisteessa käytetään esimerkkikielenä *C\#*-kieltä. Kuitenkin
31nimenomaan esimerkkinä, koska monisteen rakenne ja esimerkit voisivat
32olla aivan samanlaisia mille tahansa muullekin ohjelmointikielelle.
33Tärkeintä on nimenomaan ohjelmoinnin ajattelutavan oppiminen. Kielen
34vaihtaminen toiseen samansukuiseen kieleen on ennemmin verrattavissa
35Savon murteen vaihtamisen Turun murteeseen, kuin suomen kielen
36vaihtamisen ruotsin kieleen. Toisin sanoen, jos yhdellä kielellä on
37oppinut ohjelmoimaan, kykenee jo lukemaan toisella kielellä
38kirjoitettuja ohjelmia pienen harjoittelun jälkeen. Toisella kielellä
39kirjoittaminen on hieman haastavampaa, mutta samat rakenteet sielläkin
40toistuvat. Ohjelmointikielet tulevat ja menevät. Tätäkin vastaavaa
41kurssia on pidetty Jyväskylän yliopistossa seuraavilla kielillä:
42Fortran, Pascal, C, C++, Java ja nyt C\#. Joissakin yliopistoissa
43aloituskielenä on Python.
44
45Ohjelmointia on täysin mahdotonta oppia pelkästään kirjoja lukemalla.
46Siksi kurssi sisältää luentojen ohella myös viikoittaisten
47harjoitustehtävien (demojen) tekemistä, ohjattua pääteharjoittelua
48tietokoneluokassa sekä harjoitustyön tekemisen. Näistä lisätietoa,
49samoin kuin kurssilla käytettävien työkalujen hankkimisesta ja
50asentamisesta löytyy kurssin kotisivuilta:
51
52``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
53https://trac.cc.jyu.fi/projects/ohj1
54```
55
56Tämä moniste perustuu Martti Hyvösen ja Vesa Lappalaisen syksyllä 2009
57kirjoittamaan *Ohjelmointi 1* -monisteeseen, joka osaltaan sai muotonsa
58monen eri kirjoittajan työn tuloksena aina 80-luvulta alkaen. Suurimman
59panoksen monisteeseen ovat antaneet Timo Männikkö ja Vesa Lappalainen.
60
61Jyväskylässä 2.1.2013
62
63Martti Hyvönen, Vesa Lappalainen, Antti-Jussi Lakanen
64
651. Mitä ohjelmointi on?
66=======================
67
68Ohjelmointi on yksinkertaisimmillaan toimintaohjeiden antamista ennalta
69määrätyn toimenpiteen suorittamista varten. Ohjelmoinnin kaltaista
70toimintaa esiintyy jokaisen ihmisen arkielämässä lähes päivittäin.
71Algoritmista esimerkkinä voisi olla se, että annamme jollekulle
72puhelimessa ajo-ohjeet, joiden avulla hänen tulee päästä perille
73ennestään vieraaseen paikkaan. Tällöin luomme sarjan ohjeita ja
74komentoja, jotka ohjaavat toimenpiteen suoritusta. Alkeellista
75ohjelmointia on tavallaan myös mikroaaltouunin käyttäminen, sillä
76tällöin uunille annetaan ohjeet siitä, kuinka kauan ja kuinka suurella
77teholla sen tulee toimia.
78
79Kaikissa edellisissä esimerkeissä oli siis kyse yksikäsitteisten
80ohjeiden antamisesta. Kuitenkin esimerkit käsittelivät hyvinkin
81erilaisia viestintätilanteita. Ihmisten välinen kommunikaatio,
82mikroaaltouunin kytkimien kiertäminen tai nappien painaminen, samoin
83kuin videon ajastimen säätö laserkynällä ovat ohjelmoinnin kannalta
84toisiinsa rinnastettavissa, mutta ne tapahtuvat eri työvälineitä
85käyttäen. Ohjelmoinnissa työvälineiden valinta riippuu asetetun tehtävän
86ratkaisuun käytettävissä olevista välineistä. Ihmisten välinen
87kommunikaatio voi tapahtua puhumalla, kirjoittamalla tai näiden
88yhdistelmänä. Samoin ohjelmoinnissa voidaan usein valita erilaisia
89toteutustapoja tehtävän luonteesta riippuen.
90
91Ohjelmoinnissa on olemassa eri tasoja riippuen siitä, minkälaista
92työvälinettä tehtävän ratkaisuun käytetään. Pitkälle kehitetyt korkean
93tason työvälineet mahdollistavat työskentelyn käsitteillä ja
94ilmaisuilla, jotka parhaimmillaan muistuttavat luonnollisen kielen
95käyttämiä käsitteitä ja ilmaisuja, kun taas matalan tason työvälineillä
96työskennellään hyvin yksinkertaisilla ja alkeellisilla käsitteillä ja
97ilmaisuilla.
98
99Eräänä esimerkkinä ohjelmoinnista voidaan pitää sokerikakun
100valmistukseen kirjoitettua ohjetta:
101
102``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
103Sokerikakku
104
1056 munaa
1061,5 dl sokeria
1071,5 dl jauhoja
1081,5 tl leivinjauhetta
109
1101. Vatkaa sokeri ja munat vaahdoksi.
1112. Sekoita jauhot ja leivinjauhe.
1123. Sekoita muna-sokerivaahto ja jauhoseos.
1134. Paista 45 min 175°C lämpötilassa.
114```
115
116Valmistusohje on ilmiselvästi kirjoitettu ihmistä varten, vieläpä
117sellaista ihmistä, joka tietää leipomisesta melko paljon. Jos sama ohje
118kirjoitettaisiin ihmiselle, joka ei eläessään ole leiponut mitään, ei
119edellä esitetty ohje olisi alkuunkaan riittävä, vaan siinä täytyisi
120huomioida useita leipomiseen liittyviä niksejä: uunin ennakkoon
121lämmittäminen, vaahdon vatkauksen salat, yms.
122
123Koneelle kirjoitettavat ohjeet poikkeavat merkittävästi ihmisille
124kirjoitetuista ohjeista. Kone ei osaa automaattisesti kysyä neuvoa
125törmätessään uuteen ja ennalta arvaamattomaan tilanteeseen. Se toimii
126täsmälleen niiden ohjeiden mukaan, jotka sille on annettu, olivatpa ne
127vallitsevassa tilanteessa mielekkäitä tai eivät. Kone toistaa saamiaan
128toimintaohjeita uskollisesti sortumatta ihmisille tyypilliseen
129luovuuteen. Näin ollen tämän päivän ohjelmointikielillä koneelle
130tarkoitetut ohjeet on esitettävä hyvin tarkoin määritellyssä muodossa ja
131niissä on pyrittävä ottamaan huomioon kaikki mahdollisesti esille
132tulevat tilanteet. [MÄN]
133
1342. Ensimmäinen C\#-ohjelma
135==========================
136
1372.1 Ohjelman kirjoittaminen
138---------------------------
139
140C\#-ohjelmia (lausutaan *c sharp*) voi kirjoittaa millä tahansa
141tekstieditorilla. Tekstieditoreja on kymmeniä, ellei satoja, joten yhden
142nimeäminen on vaikeaa. Osa on kuitenkin suunniteltu varta vasten
143ohjelmointia ajatellen. Tällaiset tekstieditorit osaavat muotoilla
144ohjelmoijan kirjoittamaa lähdekoodia (tai lyhyesti koodia)
145automaattisesti siten, että lukeminen on helpompaa ja siten ymmärtäminen
146ja muokkaaminen nopeampaa. Ohjelmoijien suosimia ovat mm. *Vim,* *Emacs,
147ConTEXT* *ja* *NotePad++*, mutta monet muutkin ovat varmasti hyviä.
148Monisteen alun esimerkkien kirjoittamiseen soveltuu hyvin mikä tahansa
149tekstieditori.
150
151*Koodi, lähdekoodi =* Ohjelmoijan tuottama tiedosto, josta varsinainen
152ohjelma muutetaan tietokoneen ymmärtämäksi konekieleksi.
153
154Kirjoitetaan tekstieditorilla alla olevan mukainen C\#-ohjelma ja
155tallennetaan se vaikka nimellä HelloWorld.cs. Tiedoston tarkenteeksi
156(eli niin sanottu tiedostopääte) on sovittu juuri tuo .cs, mikä tulee
157käytetyn ohjelmointikielen nimestä, joten tälläkin kurssilla käytämme
158sitä. Kannattaa olla tarkkana tiedostoa tallennettaessa, sillä jotkut
159tekstieditorit yrittävät oletuksena tallentaa kaikki tiedostot
160tarkenteella .txt ja tällöin tiedoston nimi voi helposti tulla muotoon
161HelloWorld.cs.txt.
162
163``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
164public class HelloWorld
165{
166 public static void Main()
167 {
168 System.Console.WriteLine("Hello World!");
169 }
170}
171```
172
173Tämän ohjelman pitäisi tulostaa näytölle teksti
174
175``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
176Hello World!
177```
178
179Voidaksemme kokeilla ohjelmaa käytännössä, täytyy se ensiksi kääntää
180tietokoneen ymmärtämään muotoon.
181
182*Kääntäminen =* Kirjoitetun lähdekoodin muuntamista suoritettavaksi
183ohjelmaksi.
184
185Esimerkkejä muilla ohjelmointikielillä kirjoitetusta HelloWorld
186-ohjelmasta löydät vaikkapa:
187
188[http://www2.latech.edu/\~acm/HelloWorld.html](http://www2.latech.edu/~acm/HelloWorld.html).
189
1902.2 Ohjelman kääntäminen ja ajaminen
191------------------------------------
192
193Jotta ohjelman kääntäminen ja suorittaminen onnistuu, täytyy koneelle
194olla asennettuna joku C\#-sovelluskehitin. Mikäli käytät Windowsia, niin
195aluksi riittää hyvin Microsoft .NET SDK (Software Development Kit, suom.
196kehitystyökalut). Muiden käyttöjärjestelmien tapauksessa
197sovelluskehittimeksi käy esimerkiksi *Novell Mono*. Hyvin monet tämän
198kurssin harjoituksista on tehtävissä Mono-sovelluskehittimellä, mutta
199tämän monisteen ohjeet ja esimerkit tullaan käsittelemään
200Windows-ympäristössä. Edelleen, Jypeli-kirjaston käyttäminen on
201mahdollista vain Windows-ympäristössä.
202
203Lisätietoa .NET-kehitystyökaluista ja asentamisesta löytyy kurssin
204kotisivuilta:
205[https://trac.cc.jyu.fi/projects/ohj1/wiki/dotnet-tyokalut](https://trac.cc.jyu.fi/projects/ohj1/wiki/dotnet-tyokalut).
206Kun sovelluskehitin on asennettu, käynnistetään komentorivi (Command
207Prompt, lyhyemmin cmd) ja siirrytään siihen hakemistoon, johon
208HelloWorld.cs tiedosto on tallennettu. Ohjelma käännetään nyt
209komennolla:
210
211``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
212csc HelloWorld.cs
213```
214
215Komento ”csc” tulee sanoista *C Sharp Compiler* (compiler = kääntäjä).
216Kääntämisen jälkeen hakemistoon ilmestyy HelloWorld.exe-niminen
217tiedosto, joka voidaan ajaa kuten minkä tahansa ohjelman syöttämällä
218ohjelman nimi:
219
220``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
221HelloWorld
222```
223
224Ohjelman tulisi nyt tulostaa näyttöön teksti Hello World!, kuten alla
225olevassa kuvassa.
226
227![\
228 Kuva 1: Ohjelman kääntäminen ja ajaminen Windowsin
229komentorivillä.](../src/luentomonistecsUusin_htm_m16b63f32.png)
230
231\
232 Huomaa, että käännettäessä kirjoitetaan koko tiedoston nimi
233.cs-tarkentimen kanssa.
234
235Jos saat virheilmoituksen
236
237``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
238'csc' is not recognized as an internal or external command, operable program or batch file.
239```
240
241niin kääntäjäohjelmaa csc.exe ei silloin löydy niin sanotusta
242*hakupolusta*. Ohjelman lisääminen hakupolkuun onnistuu komennolla:
243
244``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
245set PATH=%WINDIR%\Microsoft.NET\Framework\v4.0.30319;%path%
246```
247
248Jotta kääntäjää ei tarvitsisi joka kerta lisätä hakupolkuun, voi sen
249lisätä siihen pysyvästi. Esimerkiksi Windows 7:ssä tämä tapahtuu
250seuraavasti.
251
252Klikkaa Oma tietokone -kuvaketta hiiren oikealla painikkeella ja valitse
253**Ominaisuudet** (Properties). Valitse sitten vasemmalta Advanced system
254settings ja Advanced-välilehdeltä Environment variables. Ylemmästä
255laatikosta valitse muuttuja PATH ja paina **Muokkaa**. Siirry rivin
256Variable value loppuun, kirjoita puolipiste (;) ja heti perään polku
257
258``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
259%WINDIR%\Microsoft.NET\Framework\v4.0.30319
260```
261
262XP:ssä vastaavasti Oma tietokone → Ominaisuudet → Lisäasetukset →
263Ympäristömuuttujat.
264
2652.3 Ohjelman rakenne
266--------------------
267
268Ensimmäinen kirjoittamamme ohjelma HelloWorld.cs on oikeastaan
269yksinkertaisin mahdollinen C\#-ohjelma. Alla yksinkertaisimman ohjelman
270kaksi ensimmäistä riviä.
271
272``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
273public class HelloWorld
274{
275```
276
277Ensimmäisellä rivillä määritellään *luokka* (class) jonka nimi on
278HelloWorld. Tässä vaiheessa riittää ajatella luokkaa ”kotina”
279*aliohjelmille*. Aliohjelmista puhutaan lisää hieman myöhemmin.
280Toisaalta luokkaa voidaan verrata ”piparkakkumuottiin”-se on
281rakennusohje olioiden (eli ”piparkakkujen”) luomista varten. Ohjelman
282ajamisen aikana olioita syntyy luokkaan kirjoitetun koodin avulla.
283Olioita voidaan myös tuhota. Yhdellä luokalla voidaan siis tehdä monta
284samanlaista oliota, aivan kuten yhdellä piparkakkumuotilla voidaan tehdä
285monta samanlaista (samannäköistä) piparia.
286
287Jokaisessa C\#-ohjelmassa on vähintään yksi luokka, mutta luokkia voi
288olla enemmänkin. Luokan, jonka sisään ohjelma kirjoitetaan, on hyvä olla
289samanniminen kuin tiedoston nimi. Jos tiedoston nimi on HelloWorld.cs,
290on suositeltavaa, että luokan nimi on myös HelloWorld, kuten meidän
291esimerkissämme. Tässä vaiheessa ei kuitenkaan vielä kannata liikaa
292vaivata päätänsä sillä, mikä luokka oikeastaan on, se selviää tarkemmin
293myöhemmin.
294
295Huomaa! C\#:ssa *ei* samasteta isoja ja pieniä kirjaimia. Ole siis
296tarkkana kirjoittaessasi luokkien nimiä.
297
298Huomaa! Vahva suositus (ja tämän kurssin tapa) on, että luokka alkaa
299isolla alkukirjaimella, ja ettei skandeja käytetä luokan nimessä.
300
301Luokan edessä oleva public-sana on eräs *saantimääre* (eng. *access
302modifier*). Saantimääreen avulla luokka voidaan asettaa rajoituksetta
303tai osittain muiden (luokkien) saataville, tai piilottaa kokonaan. Sana
304public tarkoittaa, että luokka on muiden luokkien näkökulmasta
305*julkinen*, kuten luokat useimmiten ovat. Muita saantimääreitä ovat
306protected, internal ja private.
307
308Määreen voi myös jättää kirjoittamatta luokan eteen, jolloin luokan
309määreeksi tulee automaattisesti internal. Puhumme aliohjelmista
310myöhemmin, mutta mainittakoon, että vastaavasti, jos aliohjelmasta
311jättää määreen kirjoittamatta, tulee siitä private. Tällä kurssilla
312kuitenkin harjoitellaan kirjoittamaan julkisia luokkia (ja aliohjelmia),
313jolloin public-sana kirjoitetaan aina luokan ja aliohjelman eteen.
314
315Toisella rivillä on oikealle auki oleva *aaltosulku*. Useissa
316ohjelmointikielissä yhteen liittyvät asiat ryhmitellään tai kootaan
317aaltosulkeiden sisälle. Oikealle auki olevaa aaltosulkua sanotaan
318aloittavaksi aaltosuluksi ja tässä tapauksessa se kertoo kääntäjälle,
319että tästä alkaa HelloWorld-luokkaan liittyvät asiat. Jokaista
320aloittavaa aaltosulkua kohti täytyy olla vasemmalle auki oleva lopettava
321aaltosulku. HelloWorld-luokan lopettava aaltosulku on rivillä viisi,
322joka on samalla ohjelman viimeinen rivi. Aaltosulkeiden rajoittamaa
323aluetta kutsutaan *lohkoksi* (block).
324
325``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
326public static void Main()
327{
328```
329
330Rivillä kolme määritellään (tai oikeammin *esitellään*) uusi aliohjelma
331nimeltä Main. Nimensä ansiosta se on tämän luokan pääohjelma. Sanat
332static ja void kuuluvat aina Main-aliohjelman esittelyyn. Paneudumme
333niihin tarkemmin hieman myöhemmin, mutta sanottakoon tässä kohtaa, että
334static tarkoittaa, että aliohjelma on *luokkakohtainen* (vastakohtana
335*oliokohtainen*, jolloin static-sanaa ei kirjoiteta). Vastaavasti void
336merkitsee, ettei aliohjelma palauta mitään tietoa.
337
338Samoin kuin luokan, niin myös pääohjelman sisältö kirjoitetaan
339aaltosulkeiden sisään. C\#:ssa ohjelmoijan kirjoittaman koodin
340suorittaminen alkaa aina käynnistettävän luokan pääohjelmasta. Toki
341sisäisesti ehtii tapahtua paljon asioita jo ennen tätä.
342
343``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
344System.Console.WriteLine("Hello World!");
345```
346
347Rivillä neljä tulostetaan näytölle Hello World!. C\#:ssa tämä tapahtuu
348pyytämällä .NET-ympäristön mukana tulevan luokkakirjaston
349System-luokkakirjaston Console-luokkaa tulostamaan
350WriteLine()-*metodilla* (method).
351
352Huomaa! Viitattaessa aliohjelmiin on kirjallisuudessa usein tapana
353kirjoittaa aliohjelman nimen perään sulut. Kirjoitustyyli korostaa, että
354kyseessä on aliohjelma, mutta asiayhteydestä riippuen sulut voi myös
355jättää kirjoittamatta. Tässä monisteessa käytetään pääsääntöisesti
356jälkimmäistä tapaa, tilanteesta riippuen.
357
358Kirjastoista, olioista ja metodeista puhutaan lisää kohdassa 4.1 ja
359luvussa 8. Tulostettava merkkijono kirjoitetaan sulkeiden sisälle
360lainausmerkkeihin (Shift + 2). Tämä rivi on myös tämän ohjelman ainoa
361*lause* (statement). Lauseiden voidaan ajatella olevan yksittäisiä
362toimenpiteitä, joista ohjelma koostuu. Jokainen lause päättyy C\#:ssa
363puolipisteeseen. Koska lauseen loppuminen ilmoitetaan puolipisteellä, ei
364C\#:n syntaksissa (syntax) ”tyhjillä merkeillä” (white space), kuten
365rivinvaihdoilla ja välilyönneillä ole merkitystä ohjelman toiminnan
366kannalta. Ohjelmakoodin luettavuuden kannalta niillä on kuitenkin suuri
367merkitys. Huomaa, että puolipisteen unohtaminen on yksi yleisimmistä
368ohjelmointivirheistä ja tarkemmin sanottuna *syntaksivirheistä.*
369
370*Syntaksi* = Tietyn ohjelmointikielen (esimerkiksi C\#:n)
371kielioppisäännöstö.
372
373### 2.3.1 Virhetyypit
374
375Ohjelmointivirheet voidaan jakaa karkeasti *syntaksivirheisiin* ja
376*loogisiin virheisiin*.
377
378Syntaksivirhe estää ohjelman kääntymisen vaikka merkitys eli
379*semantiikka* olisikin oikein. Siksi ne huomataankin aina viimeistään
380ohjelmaa käännettäessä. Syntaksivirhe voi olla esimerkiksi joku
381kirjoitusvirhe tai puolipisteen unohtaminen lauseen lopusta.
382
383Loogisissa virheissä semantiikka, eli merkitys, on väärin. Ne on
384vaikeampi huomata, sillä ohjelma kääntyy semanttisista virheistä
385huolimatta. Ohjelma voi jopa näyttää toimivan täysin oikein. Jos
386looginen virhe ei löydy *testauksessakaan* (testing), voivat seuraukset
387ohjelmistosta riippuen olla tuhoisia. Tässä yksi tunnettu esimerkki
388loogisesta virheestä:
389
390[http://money.cnn.com/magazines/fortune/fortune\_archive/2000/02/07/272831/index.htm](http://money.cnn.com/magazines/fortune/fortune_archive/2000/02/07/272831/index.htm).
391
392### 2.3.2 Kääntäjän virheilmoitusten tulkinta
393
394Alla on esimerkki syntaksivirheestä HelloWorld-ohjelmassa.
395
396``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
397public class HelloWorld
398{
399 public static void Main()
400 {
401 System.Console.Writeline("Hello World!");
402 }
403}
404```
405
406Ohjelmassa on pieni kirjoitusvirhe, joka on (ilman apuvälineitä) melko
407hankala huomata. Tutkitaan csc-kääntäjän antamaa virheilmoitusta.
408
409``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
410HelloWorld.cs(5,17): error CS0117: 'System.Console' does not contain a
411 definition for 'Writeline'
412```
413
414Kääntäjä kertoo, että tiedostossa HelloWorld.cs rivillä 5 ja sarakkeessa
41517 on seuraava virhe: System.Console-luokka ei tunne Writeline-komentoa.
416Tämä onkin aivan totta, sillä WriteLine kirjoitetaan isolla L:llä.
417Korjattuamme tuon ohjelma toimii jälleen.
418
419Valitettavasti virheilmoituksen sisältö ei aina kuvaa ongelmaa kovinkaan
420hyvin. Alla olevassa esimerkissä on erehdytty laittamaan puolipisteen
421väärään paikkaan.
422
423``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
424public class HelloWorld
425{
426 public static void Main();
427 {
428 System.Console.Writeline("Hello World!");
429 }
430}
431```
432
433Virheilmoitus, tai oikeastaan virheilmoitukset, näyttävät seuraavalta.
434
435``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
436HelloWorld.cs(4,3): error CS1519: Invalid token '{' in class, struct, or
437 interface member declaration
438HelloWorld.cs(5,26): error CS1519: Invalid token '(' in class, struct, or
439 interface member declaration
440HelloWorld.cs(7,1): error CS1022: Type or namespace definition, or end-of-file
441 expected
442```
443
444Ensimmäinen virheilmoitus osoittaa riville 4, vaikka todellisuudessa
445ongelma on rivillä 3. Toisin sanoen, näistä virheilmoituksista ei ole
446meille tässä tilanteessa lainkaan apua, päinvastoin, ne kehottavat
447tekemään jotain, mitä emme halua.
448
449### 2.3.3 Tyhjät merkit (White spaces)
450
451Esimerkkinämme ollut HelloWorld-ohjelma voitaisiin, ilman että sen
452toiminta muuttuisi, vaihtoehtoisesti kirjoittaa myös seuraavassa
453muodossa.
454
455``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
456public class HelloWorld
457 {
458
459
460 public static void Main()
461 {
462System.Console.WriteLine("Hello World!");
463 }
464
465
466}
467```
468
469\
470 \
471
472Edelleen, koodi voitaisiin kirjoittaa myös seuraavasti.
473
474``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
475public class HelloWorld { public static void Main() {
476 System.Console.WriteLine("Hello World!"); } }
477```
478
479Vaikka molemmat yllä olevista esimerkeistä ovat syntaksiltaan oikein,
480eli ne noudattavat C\#:n kielioppisääntöjä, on niiden luettavuus
481huomattavasti heikompi kuin alkuperäisen ohjelmamme. C\#:ssa on
482yhteisesti sovittuja koodauskäytänteet (code conventions), jotka
483määrittelevät, miten ohjelmakoodia tulisi kirjoittaa. Kun kaikki
484kirjoittavat samalla tavalla, on muiden koodin lukeminen helpompaa.
485Tämän monisteen esimerkit on pyritty kirjoittamaan näiden käytänteiden
486mukaisesti. Linkkejä koodauskäytänteisiin löytyy kurssin wiki-sivulta
487osoitteesta
488
489[https://trac.cc.jyu.fi/projects/ohj1/wiki/CsKoodausKaytanteet](https://trac.cc.jyu.fi/projects/ohj1/wiki/CsKoodausKaytanteet)[.](https://trac.cc.jyu.fi/projects/ohj1/wiki/CsKoodausKaytanteet)
490
491Merkkijonoja käsiteltäessä välilyönneillä, tabulaattoreilla ja
492rivinvaihdoilla on kuitenkin merkitystä. Vertaa alla olevia tulostuksia.
493
494``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
495System.Console.WriteLine("Hello World!");
496```
497
498Yllä oleva rivi tulostaa: Hello World!, kun taas alla oleva rivi
499tulostaa: H e l l o W o r l d !
500
501``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
502System.Console.WriteLine("H e l l o W o r l d !");
503```
504
5052.4 Kommentointi
506----------------
507
508> “Good programmers use their brains, but good guidelines save us having
509> to think out every case.” -Francis Glassborow
510
511Lähdekoodia on usein vaikea ymmärtää pelkkää ohjelmointikieltä
512lukemalla. Tämän takia koodin sekaan voi ja pitää lisätä selosteita eli
513*kommentteja*. Kommentit ovat sekä koodin kirjoittajaa itseään varten
514että tulevia ohjelman lukijoita ja ylläpitäjiä varten. Monet asiat
515voivat kirjoitettaessa tuntua ilmeisiltä, mutta jo viikon päästä saakin
516pähkäillä, että miksihän tuonkin tuohon kirjoitin.
517
518Kääntäjä jättää kommentit huomioimatta, joten ne eivät vaikuta ohjelman
519toimintaan. C\#:ssa on kolmenlaisia kommentteja.
520
521``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
522// Yhden rivin kommentti
523```
524
525Yhden rivin kommentti alkaa kahdella vinoviivalla (//). Sen vaikutus
526kestää koko rivin loppuun.
527
528``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
529/* Tämä kommentti
530 on usean
531 rivin
532 pituinen */
533```
534
535Vinoviivalla ja asteriskilla alkava (/\*) kommentti kestää niin kauan
536kunnes vastaan tulee asteriski ja vinoviiva ( \*/). Huomaa, ettei
537asteriskin ja vinoviivan väliin tule välilyöntiä.
538
539### 2.4.1 Dokumentointi
540
541Kolmas kommenttityyppi on *dokumentaatiokommentti*.
542Dokumentaatiokommenteissa on tietty syntaksi, ja tätä noudattamalla
543voidaan dokumentaatiokommentit muuttaa sellaiseen muotoon, että
544kommentteihin perustuvaa yhteenvetoa on mahdollista tarkastella
545nettiselaimen avulla.
546
547Dokumentaatiokommentti olisi syytä kirjoittaa ennen jokaista luokkaa,
548pääohjelmaa, aliohjelmaa ja metodia (aliohjelmista ja metodeista
549puhutaan myöhemmin). Lisäksi jokainen C\#-tiedosto alkaa aina
550dokumentaatiokommentilla, josta selviää tiedoston tarkoitus, tekijä ja
551versio.
552
553Dokumentaatiokommentit kirjoitetaan siten, että rivin alussa on aina
554aina kolme vinoviivaa (Shift + 7). Jokainen seuraava
555dokumentaatiokommenttirivi aloitetaan siis myöskin kolmella
556vinoviivalla.
557
558``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
559/// Tämä
560/// on
561/// dokumentaatiokommentti
562```
563
564Dokumentoiminen tapahtuu *tagien* avulla. Jos olet joskus kirjoittanut
565HTML-sivuja, on merkintätapa sinulle tuttu. Dokumentaatiokommentit
566alkavat aloitustagilla, muotoa \<esimerkki\>, jonka perään tulee
567kommentin asiasisältö. Kommentti loppuu lopetustagiin, muotoa
568\</esimerkki\>, siis muuten sama kuin aloitustagi, mutta ensimmäisen
569kulmasulun jälkeen on yksi vinoviiva.
570
571C\#-tageja ovat esimerkiksi \<summary\>, jolla ilmoitetaan pieni
572yhteenveto kommenttia seuraavasta koodilohkosta (esimerkiksi pääohjelma
573tai metodi). Yhteenveto päättyy \</summary\> -lopetustagiin.
574
575Ohjelman kääntämisen yhteydessä dokumentaatiotagit voidaan kirjoittaa
576erilliseen *XML*-tiedostoon, josta ne voidaan edelleen muuntaa helposti
577selattaviksi HTML-sivuiksi. Tageja voi keksiä itsekin lisää, mutta tämän
578kurssin tarpeisiin riittää hyvin suositeltujen tagien luettelo. Tiedot
579suositelluista tageista löytyvät C\#:n dokumentaatiosta:
580
581[http://msdn.microsoft.com/en-us/library/5ast78ax.aspx](http://msdn.microsoft.com/en-us/library/5ast78ax.aspx)[.](http://msdn.microsoft.com/en-us/library/5ast78ax.aspx)
582
583Voisimme kirjoittaa nyt C\#-kommentit HelloWorld-ohjelman alkuun
584seuraavasti:
585
586``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
587/// @author Antti-Jussi Lakanen
588/// @version 28.8.2012
589///
590/// <summary>
591/// Esimerkkiohjelma, joka tulostaa tekstin "Hello World!"
592/// </summary>
593
594public class HelloWorld
595{
596 /// <summary>
597 /// Pääohjelma, joka hoitaa varsinaisen tulostamisen.
598 /// </summary>
599 /// <param name="args">Ei käytössä</param>
600 public static void Main(string[] args)
601 { // Suoritus alkaa siis tästä, ohjelman "entry point"
602 System.Console.WriteLine("Hello World!"); // Tämä lause tulostaa ruudulle
603 } // Ohjelman suoritus päättyy tähän
604}
605```
606
607Ohjelman alussa kerrotaan kohteen tekijän nimi. Tämän jälkeen tulee
608ensimmäinen dokumentaatiokommentti (huomaa kolme vinoviivaa), joka on
609lyhyt ja ytimekäs kuvaus tästä luokasta. Huomaa, että jossain
610dokumentaation tiivistelmissä näytetään vain tuo ensimmäinen virke.
611[DOC] [HYV]
612
613*Dokumentointi on erittäin keskeinen osa ohjelmistotyötä*. Luokkien ja
614koodirivien määrän kasvaessa dokumentointi helpottaa niin omaa
615työskentelyä kuin tulevien käyttäjien ja ylläpitäjien tehtävää.
616Dokumentoinnin tärkeys näkyy muun muassa siinä, että jopa 40-60%
617ylläpitäjien ajasta kuluu muokattavan ohjelman ymmärtämiseen.
618[KOSK][KOS]
619
6203. Algoritmit
621=============
622
623> “First, solve the problem. Then, write the code.” - John Johnson
624
6253.1 Mikä on algoritmi?
626----------------------
627
628Pyrittäessä kirjoittamaan koneelle kelpaavia ohjeita joudutaan
629suoritettavana oleva toimenpide kirjaamaan sarjana yksinkertaisia
630toimenpiteitä. Toimenpidesarjan tulee olla yksikäsitteinen, eli sen
631tulee joka tilanteessa tarjota yksi ja vain yksi tapa toimia, eikä siinä
632saa esiintyä ristiriitaisuuksia. Yksikäsitteistä kuvausta tehtävän
633ratkaisuun tarvittavista toimenpiteistä kutsutaan algoritmiksi.
634
635Ohjelman kirjoittaminen voidaan aloittaa hahmottelemalla tarvittavat
636algoritmit eli kirjaamalla lista niistä toimenpiteistä, joita tehtävän
637suoritukseen tarvitaan:
638
639``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
640Kahvin keittäminen:
641
6421. Täytä pannu vedellä.
6432. Keitä vesi.
6443. Lisää kahvijauhot.
6454. Anna tasaantua.
6465. Tarjoile kahvi.
647```
648
649Algoritmi on yleisesti ottaen mahdollisimman pitkälle tarkennettu
650toimenpidesarja, jossa askel askeleelta esitetään yksikäsitteisessä
651muodossa ne toimenpiteet, joita asetetun ongelman ratkaisuun tarvitaan.
652
6533.2 Tarkentaminen
654-----------------
655
656Kun tarkastellaan lähes mitä tahansa tehtävänantoa, huomataan, että
657tehtävän suoritus koostuu selkeästi toisistaan eroavista osatehtävistä.
658Se, miten yksittäinen osatehtävä ratkaistaan, ei vaikuta muiden
659osatehtävien suorittamiseen. Vain sillä, että kukin osasuoritus tehdään,
660on merkitystä. Esimerkiksi pannukahvinkeitossa jokainen osatehtävä
661voidaan jakaa edelleen osasiin:
662
663``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
664Kahvinkeitto:
665
6661. Täytä pannu vedellä:
667 1.1. Pistä pannu hanan alle.
668 1.2. Avaa hana.
669 1.3. Anna veden valua, kunnes vettä on riittävästi.
6702. Keitä vesi:
671 2.1. Aseta pannu hellalle.
672 2.2. Kytke virta keittolevyyn.
673 2.3. Anna lämmetä, kunnes vesi kiehuu.
6743. Lisää kahvinporot:
675 3.1. Mittaa kahvinporot.
676 3.2. Sekoita kahvinporot kiehuvaan veteen.
6774. Anna tasaantua:
678 4.1. Odota, kunnes suurin osa valmiista kahvista on vajonnut
679 pannun pohjalle.
6805. Tarjoile kahvi:
681 5.1. Tämä sitten onkin jo oma tarinansa...
682```
683
684Edellä esitetyn kahvinkeitto-ongelman ratkaisu esitettiin jakamalla
685ratkaisu viiteen osavaiheeseen. Ratkaisun algoritmi sisältää viisi
686toteutettavaa lausetta. Kun näitä viittä lausetta tarkastellaan
687lähemmin, osoittautuu, että niistä kukin on edelleen jaettavissa
688osavaiheisiin, eli ratkaisun pääalgoritmi voidaan jakaa edelleen
689alialgoritmeiksi, joissa askel askeleelta esitetään, kuinka kukin
690osatehtävä ratkaistaan.
691
692Algoritmien kirjoittaminen osoittautuu hierarkkiseksi prosessiksi, jossa
693aluksi tehtävä jaetaan osatehtäviin, joita edelleen tarkennetaan, kunnes
694kukin osatehtävä on niin yksinkertainen, ettei sen suorittamisessa enää
695ole mitään moniselitteistä.
696
6973.3 Yleistäminen
698----------------
699
700Eräs tärkeä algoritmien kirjoittamisen vaihe on yleistäminen. Tällöin
701valmiiksi tehdystä algoritmista pyritään paikantamaan kaikki alunperin
702annetusta tehtävästä riippuvat tekijät, ja pohditaan voitaisiinko ne
703kenties kokonaan poistaa tai korvata joillakin yleisemmillä tekijöillä.
704
7053.4 Harjoitus
706-------------
707
708Tarkastele edellä esitettyä algoritmia kahvin keittämiseksi ja luo
709vastaava algoritmi teen keittämiseksi. Vertaile algoritmeja: mitä samaa
710ja mitä eroa niissä on? Onko mahdollista luoda algoritmi, joka
711yksiselitteisesti selviäisi sekä kahvin että teen keitosta? Onko
712mahdollista luoda algoritmi, joka saman tien selviytyisi maitokaakosta
713ja rommitotista?
714
7153.5 Peräkkäisyys
716----------------
717
718Kuten luvussa 1 olevassa reseptissä ja muissakin ihmisille
719kirjoitetuissa ohjeissa, niin myös tietokoneelle esitetyt ohjeet luetaan
720ylhäältä alaspäin, ellei muuta ilmoiteta. Esimerkiksi ohjeen lumiukon
721piirtämisestä voisi esittää yksinkertaistettuna alla olevalla tavalla.
722
723``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
724Piirrä säteeltään 20cm kokoinen ympyrä koordinaatiston pisteeseen (20, 80)
725Piirrä säteeltään 15cm kokoinen ympyrä edellisen ympyrän päälle
726Piirrä säteeltään 10cm kokoinen ympyrä edellisen ympyrän päälle
727```
728
729Yllä oleva koodi ei ole vielä mitään ohjelmointikieltä, mutta se
730sisältää jo ajatuksen siitä kuinka lumiukko voitaisiin tietokoneella
731piirtää. Piirrämme lumiukon C\#-ohjelmointikielellä seuraavassa luvussa.
732
7334. Yksinkertainen graafinen C\#-ohjelma
734=======================================
735
736Seuraavissa esimerkeissä käytetään Jyväskylän yliopistossa
737kehitettyä*Jypeli-ohjelmointikirjastoa.* Kirjaston voit ladata koneelle
738osoitteesta
739
740[https://trac.cc.jyu.fi/projects/npo/wiki/LataaJypeli](https://trac.cc.jyu.fi/projects/npo/wiki/LataaJypeli),
741
742josta löytyy myös ohjeet kirjaston asennukseen ja käyttöön. Huomaa, että
743tietokoneellasi tulee olla asennettuna .NET Framework 4 sekä XNA Game
744Studio 4, jotta graafinen ohjelma voidaan kääntää. .NET-frameworkin
745asennusohjeet löytyvät osoitteesta
746
747[https://trac.cc.jyu.fi/projects/ohj1/wiki/dotnet-tyokalut](https://trac.cc.jyu.fi/projects/ohj1/wiki/dotnet-tyokalut).
748
749Vaikka tässä kohtaa emme vielä Visual Studio 2010 -kehitysympäristöä
750tarvitsekaan, on sen asentaminen tässä kohtaa myös viisasta, sillä
751Visual Studio tulisi olla asennettuna ennen XNA:n ja Jypelin
752asentamista.
753
7544.1 Mikä on kirjasto?
755---------------------
756
757C\#-ohjelmat koostuvat luokista. Luokat taas sisältävät metodeja (ja
758aliohjelmia), jotka suorittavat tehtäviä ja mahdollisesti palauttavat
759arvoja suoritettuaan näitä tehtäviä. Metodi voisi esimerkiksi laskea
760kahden luvun summan ja palauttaa tuloksen tai piirtää ohjelmoijan
761haluaman kokoisen ympyrän. Samaan asiaan liittyviä metodeja kootaan
762luokkaan ja luokkia kootaan edelleen kirjastoiksi. Idea kirjastoissa on,
763ettei kannata tehdä uudelleen sitä minkä joku on jo tehnyt. Toisin
764sanoen, pyörää ei kannata keksiä uudelleen.
765
766C\#-ohjelmoijan kannalta oleellisin kirjasto on .NET Framework
767luokkakirjasto. Luokkakirjaston dokumentaatioon (documentation)
768kannattaa tutustua, sillä sieltä löytyy monia todella hyödyllisiä
769metodeja. Dokumentaatio löytyy Microsoftin sivuilta osoitteesta
770
771[http://msdn.microsoft.com/en-us/library/ms229335.aspx](http://msdn.microsoft.com/en-us/library/ms229335.aspx).
772
773*Dokumentaatio =* Sisältää tiedot kaikista kirjaston luokista ja niiden
774metodeista (ja aliohjelmista). Löytyy useimmiten ainakin WWW-muodossa.
775
7764.2 Jypeli-kirjasto
777-------------------
778
779Jypeli-kirjaston kehittäminen aloitettiin Jyväskylän yliopistossa
780keväällä 2009. Tämän monisteen esimerkeissä käytetään versiota 4.
781Jypeli-kirjastoon on kirjoitettu valmiita luokkia ja metodeja siten,
782että esimerkiksi fysiikan ja matematiikan ilmiöiden, sekä pelihahmojen
783ja liikkeiden ohjelmointi lopulliseen ohjelmaan on helpompaa.
784
7854.3 Esimerkki: Lumiukko
786-----------------------
787
788Piirretään lumiukko käyttämällä Jypeli-kirjastoa. Mallikoodin vasemmassa
789reunassa juoksee myös rivinumerointi, joka ei kuulu koodiin, mutta
790helpottaa lukemista.
791
792``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
79301 // Otetaan käyttöön Jyväskylän yliopiston Jypeli-kirjasto
79402 using Jypeli;
79503
79604 /// @author Vesa Lappalainen, Antti-Jussi Lakanen
79705 /// @version 22.12.2011
79806 ///
79907 ///
80008 /// <summary>
80109 /// Luokka, jossa harjoitellaan piirtämistä lisäämällä ympyröitä ruudulle
80210 /// </summary>
80311 public class Lumiukko : PhysicsGame
80412 {
80513 /// <summary>
80614 /// Pääohjelmassa laitetaan "peli" käyntiin Jypelille tyypilliseen tapaan
80715 /// </summary>
80816 /// <param name="args">Ei käytössä</param>
80917 public static void Main(string[] args)
81018 {
81119 using (Lumiukko peli = new Lumiukko())
81220 {
81321 peli.Run();
81422 }
81523 }
81624
81725 /// <summary>
81826 /// Piirretään oliot ja zoomataan kamera niin että kenttä näkyy kokonaan.
81927 /// </summary>
82028 public override void Begin()
82129 {
82230 Camera.ZoomToLevel();
82331 Level.Background.Color = Color.Black;
82432
82533 PhysicsObject p1 = new PhysicsObject(2*100.0, 2*100.0, Shape.Circle);
82634 p1.Y = Level.Bottom + 200.0;
82735 Add(p1);
82836
82937 PhysicsObject p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
83038 p2.Y = p1.Y + 100 + 50;
83139 Add(p2);
83240
83341 PhysicsObject p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
83442 p3.Y = p2.Y + 50 + 30;
83543 Add(p3);
83644 }
83745 }
838```
839
840Ajettaessa ohjelman tulisi piirtää yksinkertainen lumiukko keskelle
841ruutua, kuten alla olevassa kuvassa. 4.3.1 Ohjelman suoritus
842
843![\
844 Kuva 2: Lumiukko Jypeli-kirjaston avulla
845piirrettynä](../src/luentomonistecsUusin_htm_m793342fb.png)
846
847\
848
849### 4.3.1 Ohjelman suoritus
850
851Ohjelman suoritus aloitetaan aina pääohjelmasta ja sitten edetään rivi
852riviltä ylhäältä alaspäin ohjelman loppuun niin kauan kuin lauseita
853riittää. Ohjelmassa voi olla myös rakenteita, joissa toistetaan tiettyjä
854rivejä useampaan kertaan vain muuttamalla jotain arvoa tai arvoja.
855Pääohjelmassa voi olla myös aliohjelmakutsuja jolloin hypätään
856pääohjelmasta suorittamaan aliohjelmaa ja palataan sitten takaisin
857pääohjelman suoritukseen. Aliohjelmista puhutaan enemmän luvussa 6.
858
859### 4.3.2 Ohjelman oleellisemmat kohdat
860
861Tarkastellaan ohjelman oleellisempia kohtia.
862
863``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
86402 using Jypeli;
865```
866
867Aluksi meidän täytyy kertoa kääntäjälle, että haluamme ottaa käyttöön
868koko Jypeli-kirjaston. Nyt Jypeli-kirjaston kaikki luokat (ja niiden
869metodit) ovat käytettävissämme.
870
871``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
87208 /// <summary>
87309 /// Luokka, jossa harjoitellaan piirtämistä lisäämällä ympyröitä ruudulle
87410 /// </summary>
87511 public class Lumiukko : PhysicsGame
87612 {
877```
878
879Rivit 8-10 ovat dokumentaatiokommentteja. Rivillä 11 luodaan
880Lumiukko-luokka, joka hieman poikkeaa HelloWorld-esimerkin tavasta luoda
881uusi luokka. Tässä kohtaa käytämme ensimmäisen kerran Jypeli-kirjastoa,
882ja koodissa kerrommekin, että Lumiukko-luokka, jota juuri olemme
883tekemässä, ”perustuu” Jypeli-kirjastossa olevaan PhysicsGame-luokkaan.
884Täsmällisemmin sanottuna Lumiukko-luokka peritään PhysicsGame-luokasta.
885Tuon PhysicsGame-luokan avulla objektien piirtäminen, myöhemmin
886liikuttelu ruudulla ja fysiikan lakien hyödyntäminen on vaivatonta.
887
888``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
88913 /// <summary>
89014 /// Pääohjelmassa laitetaan "peli" käyntiin Jypelille tyypilliseen tapaan.
89115 /// </summary>
89216 /// <param name="args">Ei käytössä</param>
89317 public static void Main(String[] args)
89418 {
89519 using (Lumiukko peli = new Lumiukko())
89620 {
89721 peli.Run();
89822 }
89923 }
900```
901
902Myös Main-metodi, eli pääohjelma, on Jypeli-peleissä käytännössä aina
903tällainen vakiomuotoinen, joten jatkossa siihen ei tarvitse juurikaan
904koskea. Ohitamme tässä vaiheessa pääohjelman sisällön mainitsemalla
905vain, että pääohjelmassa Lumiukko-luokasta tehdään uusi olio (eli uusi
906”peli”), joka sitten laitetaan käyntiin peli.Run()-kohdassa.
907Jypeli-kirjaston rakenteesta johtuen kaikki varsinainen peliin liittyvä
908koodi kirjoitetaan omaan aliohjelmaansa, Begin-aliohjelmaan, jota
909käsittelemme seuraavaksi.
910
911Tarkasti ottaen Begin alkaa riviltä 29. Ensimmäinen lause on kirjoitettu
912riville 30.
913
914``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
91530 Camera.ZoomToLevel();
91631 Level.Background.Color = Color.Black;
917```
918
919Näistä kahdesta rivistä ensimmäisellä kutsutaan Camera-luokan
920ZoomToLevel-aliohjelmaa, joka pitää huolen siitä, että ”kamera” on
921kohdistettuna ja zoomattuna oikeaan kohtaan. Aliohjelma ei ota vastaan
922parametreja, joten sulkujen sisältö jää tyhjäksi. Toisella rivillä
923muutetaan taustan väri.
924
925``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
92633 PhysicsObject p1 = new PhysicsObject(2*100.0, 2*100.0, Shape.Circle);
92734 p1.Y = Level.Bottom + 200.0;
92835 Add(p1);
929```
930
931Näiden kolmen rivin aikana luomme uuden fysiikkaolio-ympyrän, annamme
932sille säteen, y-koordinaatin, sekä lisäämme sen ”pelikentälle”, eli
933näkyvälle alueelle valmiissa ohjelmassa.
934
935Tarkemmin sanottuna luomme uuden PhysicsObject-*olion* eli
936PhysicsObject-luokan *ilmentymän*, jonka nimeksi annamme p1.
937PhysicsObject-oliot ovat pelialueella liikkuvia olioita, jotka
938noudattavat fysiikan lakeja. Sulkujen sisään laitamme tiedon siitä,
939millaisen objektin haluamme luoda - tässä tapauksessa leveys ja korkeus
940(Jypeli-mitoissa, ei pikseleissä), sekä olion muoto. Teemme siis
941ympyrän, jonka säde on 100 (leveys 2 \* 100 ja korkeus 2 \* 100). Muita
942Shape-kokoelmasta löytyviä muotoja ovat muiden muassa kolmio, neliö,
943sydän jne. Olioista puhutaan lisää luvussa 8.
944
945Kokeile itse muuttaa olion muotoa!
946
947Seuraavalla rivillä asetetaan olion paikka Y-arvon avulla. Huomaa että Y
948kirjoitetaan isolla kirjaimella. Tämä on p1-olion ominaisuus,
949attribuutti. X-koordinaattia meidän ei tarvitse tässä erikseen asettaa,
950se on oletusarvoisesti 0 ja se kelpaa meille. Saadaksemme ympyrät
951piirrettyä oikeille paikoilleen, täytyy meidän laskea koordinaattien
952paikat. Oletuksena ikkunan keskipiste on koordinaatiston origo eli piste
953(0, 0). x-koordinaatin arvot kasvavat oikealle ja y:n arvot ylöspäin,
954samoin kuin ”normaalissa” koulusta tutussa koordinaatistossa.
955
956Peliolio täytyy aina lisätä kentälle, ennen kuin se saadaan näkyviin.
957Tämä tapahtuu Add-metodin avulla, joka ottaa parametrina kentälle
958lisättävän olion nimen (tässä p1).
959
960Metodeille annettavia tietoja sanotaan *parametreiksi* (parameter).
961ZoomToLevel-metodi ei ota vastaan yhtään parametria, mutta Add-metodi
962sen sijaan ottaa yhden parametrin: PhysicsObject-tyyppisen olion.
963Add-metodille voidaan antaa toinenkin parametri: *taso*, jolle olio
964lisätään. Tasojen avulla voidaan hallita, mitkä oliot lisätään
965päällimmäiseksi. Tasoparametri voidaan kuitenkin jättää antamatta,
966jolloin ohjelma itse päättää tasojen parhaan järjestyksen. Parametrit
967kirjoitetaan metodin nimen perään sulkeisiin ja ne erotetaan toisistaan
968pilkuilla.
969
970``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
971MetodinNimi(parametri1, parametri2,..., parametriX);
972```
973
974Seuraavien rivien aikana luomme vielä kaksi ympyrää vastaavalla tavalla,
975mutta vaihtaen sädettä ja ympyrän koordinaatteja.
976
977Esimerkissä koordinaattien laskemiseen on käytetty C\#:n *aritmeettisia
978operaatioita*. Voisimme tietenkin laskea koordinaattien pisteet myös
979itse, mutta miksi tehdä niin jos tietokone voi laskea pisteet
980puolestamme? C\#:n aritmeettiset perusoperaatiot ovat summa (+),
981vähennys (-), kerto (\*), jako (/) ja jakojäännös (%). Aritmeettisista
982operaatioista puhutaan lisää muuttujien yhteydessä kohdassa 7.7.1.
983
984Keskimmäinen ympyrä tulee alimman ympyrän yläpuolelle niin, että ympyrät
985sivuavat toisiaan. Keskimmäisen ympyrän keskipiste sijoittuu siis siten,
986että sen x-koordinaatti on 0 ja y-koordinaatti on *alimman ympyrän
987paikka* +*alimman ympyrän säde + keskimmäisen ympyrän säde*. Kun
988haluamme, että keskimmäisen ympyrän säde on 50, niin silloin
989keskimmäisen ympyrän keskipiste tulee kohtaan (0, p1.Y + 100 + 50) ja se
990piirretään lauseella:
991
992``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
993PhysicsObject p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
994p2.Y = p1.Y + 100 + 50;
995Add(p2);
996```
997
998Huomaa, että fysiikkaolion Y-ominaisuuden asettamisen (*set*) lisäksi
999voimme myös lukea tai pyytää (*get*) kyseisen ominaisuuden arvon. Yllä
1000teemme sen kirjoittamalla yksinkertaisesti sijoitusoperaattorin oikealle
1001puolelle p1.Y.
1002
1003Seuraava kuva havainnollistaa ensimmäisen ja toisen pallon asettelua.
1004
1005![\
1006 Kuva 3: Lumiukon kaksi ensimmäistä palloa asemoituina
1007paikoilleen.](../src/luentomonistecsUusin_htm_m58b94a29.png)
1008
1009\
1010 \
1011 \
1012
1013Ylin ympyrä sivuaa sitten taas keskimmäistä ympyrää. Harjoitustehtäväksi
1014jätetään laskea ylimmän ympyrän koordinaatit, kun ympyrän säde on 30.
1015
1016Kaikki tiedot luokista, luokkien metodeista sekä siitä mitä parametreja
1017metodeille tulee antaa löydät käyttämäsi kirjaston dokumentaatiosta.
1018Jypelin luokkadokumentaatio löytyy osoitteesta:
1019[http://kurssit.it.jyu.fi/npo/material/latest/documentation/html/](http://kurssit.it.jyu.fi/npo/material/latest/documentation/html/).
1020
10214.4 Harjoitus
1022-------------
1023
1024Etsi Jypeli-kirjaston dokumentaatiosta RandomGen-luokka. Mitä tietoa
1025löydät NextInt(int min, int max)-metodista? Mitä muita metodeja luokassa
1026on?
1027
10284.5 Kääntäminen ja luokkakirjastoihin viittaaminen
1029--------------------------------------------------
1030
1031Jotta Lumiukko-esimerkkiohjelma voitaisiin nyt kääntää C\#-kääntäjällä,
1032tulee Jypeli-kirjasto olla tallennettuna tietokoneelle. Jypeli käyttää
1033XNA-kirjaston lisäksi vapaan lähdekoodin fysiikka- ja
1034matematiikkakirjastoja. Fysiikka- ja matematiikkakirjastot on
1035sisäänrakennettuina Jypeli-kirjastoon.
1036
1037Ennen kääntämistä kopioi seuraavat tiedostot kurssin kotisivuilta
1038([https://trac.cc.jyu.fi/projects/ohj1/wiki/csharpCommandLine](https://trac.cc.jyu.fi/projects/ohj1/wiki/csharpCommandLine))
1039samaan kansioon Lumiukko.cs-tiedoston kanssa.
1040
1041- Jypeli.dll
1042
1043Meidän täytyy vielä välittää kääntäjälle tieto siitä, että
1044Jypeli-kirjastoa tarvitaan Lumiukko-koodin kääntämiseen. Lisäksi
1045annetaan kääntäjälle tieto siitä, että ohjelma tehdään *32-bittisille*
1046järjestelmille (x86). Tämä tehdään csc-ohjelman
1047`/reference`{.terminaali-western}-parametrin avulla. Lisäksi tarvitaan
1048referenssi Jypelin käyttämään XNA-kirjastoon. Kirjoita nyt
1049komentoriville(kaikki rivit samalle riville niin, että /-viivan edessä
1050on yksi välilyönti)
1051
1052``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1053csc Lumiukko.cs /reference:Jypeli.dll;"%XNAGSv4%\References\Windows\x86\Microsoft.Xna.Framework.Game.dll" /platform:x86
1054```
1055
1056Jos käyttöjärjestelmäsi ei tunnista csc-komentoa, niin kertaa luvussa 2
1057olevat ohjeet komennon asettamisesta
1058`PATH`{.terminaali-western}-ympäristömuuttujan poluksi.
1059
1060Vinkki! Yllä esitelty kääntämiskomento on varsin pitkä. Asioiden
1061helpottamiseksi voit kirjoittaa tiedoston csk.bat, joka sisältää
1062seuraavan tekstin (komento on yksi pitkä rivi):\
1063 \
1064@"%WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\csc" %\*
1065/reference:Jypeli.dll;"%XNAGSv4%References\\Windows\\x86\\Microsoft.Xna.Framework.Game.dll";"%XNAGSv4%References\\Windows\\x86\\Microsoft.Xna.Framework.dll"
1066/platform:x86 /define:WINDOWS\
1067 \
1068Tämä asettaa puolestasi reference ja platform -parametrit. Varmista,
1069että tekemäsi csk.bat-tiedosto on ”polussa”. Tämän jälkeen kääntäminen
1070onnistuu yksinkertaisemmin: csk OhjelmanNimi.cs
1071
10725. Lähdekoodista prosessorille
1073==============================
1074
10755.1 Kääntäminen
1076---------------
1077
1078Tarkastellaan nyt tarkemmin sitä kuinka C\#-lähdekoodi muuttuu lopulta
1079prosessorin ymmärtämään muotoon. Kun ohjelmoija luo ohjelman
1080lähdekoodin, joka käyttää *.NET Framework* -ympäristöä, tapahtuu
1081kääntäminen sisäisesti kahdessa vaiheessa. Ohjelma käännetään ensin
1082eräänlaiselle välikielelle, *MSIL*:lle (Microsoft Intermediate
1083Language), joka ei ole vielä suoritettavissa millään
1084käyttöjärjestelmällä. Tästä välivaiheen koodista käännetään ajon aikana
1085valmis ohjelma halutulle käyttöjärjestelmälle, kuten Mac Os X:lle tai
1086Linuxille, niin sanotulla *JIT-kääntäjällä* (Just-In-Time). JIT-kääntäjä
1087muuntaa välivaiheen koodin juuri halutulle käyttöjärjestelmälle
1088sopivaksi koodiksi nimenomaan ohjelmaa ajettaessa - tästä tulee nimi
1089”just-in-time”.
1090
1091Ennen ensimmäistä kääntämistä kääntäjä tarkastaa, että koodi on
1092syntaksiltaan oikein. [VES][KOS]
1093
1094Kääntäminen tehtiin Windowsissa komentorivillä (Command Prompt)
1095käyttämällä komentoa
1096
1097``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1098csc Tiedostonnimi.cs
1099```
1100
1101tai hyödyntämällä edellisessä luvussa esiteltyä komentojonoa
1102
1103``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1104csk Tiedostonnimi.cs
1105```
1106
11075.2 Suorittaminen
1108-----------------
1109
1110C\#:n tuottaa siis lähdekoodista suoritettavan (tai ”ajettavan”)
1111tiedoston. Tämä tiedosto on käyttöjärjestelmäriippuvainen, ja
1112suoritettavissa vain sillä alustalla, johon käännös on tehty. Toisin
1113sanoen, Windows-ympäristössä käännetyt ohjelmat eivät ole ajettavissa OS
1114X -käyttöjärjestelmässä, ja toisin päin.
1115
1116Toisin kuin C\#, eräät toiset ohjelmointikielet tuottavat
1117käyttöjärjestelmäriippumatonta koodia. Esimerkiksi *Java*-kielessä
1118kääntäjän tuottama tiedosto on niin sanottua *tavukoodia*, joka on
1119käyttöjärjestelmäriippumatonta koodia. Tavukoodin suorittamiseen
1120tarvitaan Java-virtuaalikone (Java Virtual Machine). Java-virtuaalikone
1121on oikeaa tietokonetta matkiva ohjelma, joka tulkkaa tavukoodia ja
1122suorittaa sitä sitten kohdekoneen prosessorilla. Tässä on merkittävä ero
1123perinteisiin käännettäviin kieliin (esimerkiksi C ja C++), joissa
1124käännös on tehtävä erikseen jokaiselle eri laitealustalle. [VES][KOS]
1125
1126\
1127 \
1128
11296. Aliohjelmat
1130==============
1131
1132> “Copy and paste is a design error.” - David Parnas
1133
1134Pääohjelman lisäksi ohjelma voi sisältää muitakin aliohjelmia.
1135Aliohjelmaa *kutsutaan* pääohjelmasta, metodista tai toisesta
1136aliohjelmasta suorittamaan tiettyä tehtävää. Aliohjelmat voivat saada
1137parametreja ja palauttaa arvon, kuten metoditkin. Pohditaan seuraavaksi
1138mihin aliohjelmia tarvitaan.
1139
1140Jos tehtävänämme olisi piirtää useampi lumiukko, niin tämänhetkisellä
1141tietämyksellämme tekisimme todennäköisesti jonkin alla olevan kaltaisen
1142ratkaisun.
1143
1144``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
114501 using Jypeli;
114602
114703 /// <summary>
114804 /// Piirretään lumiukko.
114905 /// </summary>
115006 public class Lumiukko : PhysicsGame
115107 {
115208 /// <summary>
115309 /// Pääohjelmassa peli käyntiin.
115410 /// </summary>
115511 /// <param name="args">Ei käytössä.</param>
115612 public static void Main(String[] args)
115713 {
115814 using (Lumiukko game = new Lumiukko())
115915 {
116016 game.Run();
116117 }
116218 }
116319
116420 /// <summary>
116521 /// Aliohjelma, jossa
116622 /// piirretään ympyrät.
116723 /// </summary>
116824 public override void Begin()
116925 {
117026 Camera.ZoomToLevel();
117127 Level.Background.Color = Color.Black;
117228
117329 PhysicsObject p1, p2, p3;
117430
117531 // Eka ukko
117632 p1 = new PhysicsObject(2 * 100.0, 2 * 100.0, Shape.Circle);
117733 p1.Y = Level.Bottom + 200.0;
117834 Add(p1);
117935
118036 p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
118137 p2.Y = p1.Y + 100 + 50;
118238 Add(p2);
118339
118440 p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
118541 p3.Y = p2.Y + 50 + 30;
118642 Add(p3);
118743
118844 // Toinen ukko
118945 p1 = new PhysicsObject(2 * 100.0, 2 * 100.0, Shape.Circle);
119046 p1.X = 200;
119147 p1.Y = Level.Bottom + 300.0;
119248 Add(p1);
119349
119450 p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
119551 p2.X = 200;
119652 p2.Y = p1.Y + 100 + 50;
119753 Add(p2);
119854
119955 p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
120056 p3.X = 200;
120157 p3.Y = p2.Y + 50 + 30;
120258 Add(p3);
120359 }
120460 }
1205```
1206
1207Huomataan, että ensimmäisen ja toisen lumiukon piirtäminen tapahtuu
1208lähes samanlaisilla koodinpätkillä. Itse asiassa ainoa ero on, että
1209jälkimmäisen lumiukon pallot saavat ensimmäisestä lumiukosta eroavat
1210koordinaatit. Toisaalta voisimme kirjoittaa koodin myös niin, että
1211lumiukon alimman pallon keskipiste tallennetaan *muuttujiin* x ja y.
1212Näiden pisteiden avulla voimme sitten laskea muiden pallojen paikat.
1213Määritellään heti alussa myös p1, p2 ja p3 PhysicsObject-olioiksi.
1214Rivinumerointi on tässä jätetty pois selvyyden vuoksi. Luvun lopussa
1215korjattu ohjelma esitellään kokonaisuudessaan rivinumeroinnin kanssa.
1216
1217``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1218double x, y;
1219PhysicsObject p1, p2, p3;
1220
1221// Tehdään ensimmäinen lumiukko
1222x = 0; y = Level.Bottom + 200.0;
1223p1 = new PhysicsObject(2*100.0, 2*100.0, Shape.Circle);
1224p1.X = x;
1225p1.Y = y;
1226Add(p1);
1227
1228p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
1229p2.X = x;
1230p2.Y = y + 100 + 50; // y + 1. pallon säde + 2. pallon säde
1231Add(p2);
1232
1233p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
1234p3.X = x;
1235p3.Y = y + 100 + 2 * 50 + 30; // y + 1. pallon säde + 2. halk. + 3. säde
1236Add(p3);
1237```
1238
1239Vastaavasti toiselle lumiukolle: asetetaan vain x:n ja y:n arvot
1240oikeiksi.
1241
1242``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1243// Tehdään toinen lumiukko
1244x = 200; y = Level.Bottom + 300.0;
1245p1 = new PhysicsObject(2 * 100.0, 2 * 100.0, Shape.Circle);
1246p1.X = x;
1247p1.Y = y;
1248Add(p1);
1249
1250p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
1251p2.X = x;
1252p2.Y = y + 100 + 50;
1253Add(p2);
1254
1255p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
1256p3.X = x;
1257p3.Y = y + 100 + 2*50 + 30;
1258Add(p3);
1259```
1260
1261Tarkastellaan nyt muutoksia hieman tarkemmin.
1262
1263``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1264double x, y;
1265```
1266
1267Yllä olevalla rivillä esitellään kaksi liukuluku*tyyppistä* *muuttujaa*.
1268Liukuluku on eräs tapa esittää *reaalilukuja* tietokoneissa. C\#:ssa
1269jokaisella muuttujalla on oltava tyyppi ja eräs liukulukutyyppi C\#:ssa
1270on double. Muuttujista ja niiden tyypeistä puhutaan lisää luvussa 7.
1271
1272*Liukuluku* (floating point) = Tietokoneissa käytettävä esitysmuoto
1273reaaliluvuille. Tarkempaa tietoa liukuluvuista löytyy luvusta 26.
1274
1275\
1276
1277``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1278x = 0; y = Level.Bottom + 200.0;
1279```
1280
1281Yllä olevalla rivillä on kaksi lausetta. Ensimmäisellä asetetaan
1282muuttujaan x arvo 0 ja toisella muuttujaan y arvo 50 (jos Level.Bottom
1283sattuu olemaan vaikka -150). Nyt voimme käyttää lumiukon pallojen
1284laskentaan näitä muuttujia.
1285
1286``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1287x = 300; y = Level.Bottom + 300.0;
1288```
1289
1290Vastaavasti yllä olevalla rivillä asetetaan nyt muuttujiin uudet arvot,
1291joita käytetään seuraavan lumiukon pallojen paikkojen laskemiseen.
1292Huomaa, että y-koordinaatti saa negatiivisen arvon, jolloin lumiukon
1293alimman pallon keskipiste painuu kuvaruudun keskitason alapuolelle.
1294
1295Nyt alimman pallon x-koordinaatiksi sijoitetaankin *muuttuja* x, ja
1296vastaavasti y-koordinaatin arvoksi asetetaan *muuttuja* y, ja muiden
1297pallojen sijainnit lasketaan ensimmäisen pallon koordinaattien
1298perusteella.
1299
1300![\
1301 Kuva 4: Kaksi
1302lumiukkoa.](../src/luentomonistecsUusin_htm_m12339dd1.png)
1303
1304\
1305 Näiden muutosten jälkeen molempien lumiukkojen varsinainen piirtäminen
1306tapahtuu nyt **täysin samalla koodilla**.
1307
1308Uusien lumiukkojen piirtäminen olisi nyt jonkin verran helpompaa, sillä
1309meidän ei tarvitse kuin ilmoittaa ennen piirtämistä uuden lumiukon
1310paikka ja varsinaisen lumiukkojen piirtäminen onnistuisi kopioimilla ja
1311liittämällä koodia (copy-paste). Kuitenkin, jos koodia kirjoittaessa
1312joutuu tekemään suoraa kopiointia, pitäisi pysähtyä miettimään, että
1313onko tässä mitään järkeä.
1314
1315Kahden lumiukon tapauksessa tämä vielä onnistuu ilman, että koodin määrä
1316kasvaa kohtuuttomasti, mutta entä jos meidän pitäisi piirtää 10 tai 100
1317lumiukkoa? Kuinka monta riviä ohjelmaan tulisi silloin? Kun lähes
1318samanlainen koodinpätkä tulee useampaan kuin yhteen paikkaan, on
1319useimmiten syytä muodostaa siitä oma *aliohjelma*. Koodin monistaminen
1320moneen paikkaan lisäisi vain koodirivien määrää, tekisi ohjelman
1321ymmärtämisestä vaikeampaa ja vaikeuttaisi testaamista.
1322
1323\
1324 \
1325
1326Lisäksi jos monistetussa koodissa olisi vikaa, jouduttaisiin korjaukset
1327tekemään myös useampaan paikkaan. Hyvän ohjelman yksi mitta (kriteeri)
1328onkin, että jos jotain pitää muuttaa, niin kohdistuvatko muutokset
1329kohdistuvat vain yhteen paikkaan (hyvä) vai joudutaanko muutoksia
1330tekemään useaan paikkaan (huono).
1331
13326.1 Aliohjelman kutsuminen
1333--------------------------
1334
1335Haluamme siis aliohjelman, joka piirtää meille lumiukon tiettyyn
1336pisteeseen. Kuten metodeille, myös aliohjelmalle viedään parametrien
1337avulla sen tarvitsemaa tietoa. Parametreina tulisi viedä vain
1338minimaaliset tiedot, joilla aliohjelman tehtävä saadaan suoritettua.
1339
1340Sovitaan, että aliohjelmamme piirtää aina samankokoisen lumiukon
1341haluamaamme pisteeseen. Mitkä ovat ne välttämättömät tiedot, jotka
1342aliohjelma tarvitsee piirtääkseen lumiukon?
1343
1344Aliohjelma tarvitsee tiedon *mihin* pisteeseen lumiukko piirretään.
1345Viedään siis parametrina lumiukon alimman pallon keskipiste. Muiden
1346pallojen paikat voidaan laskea tämän pisteen avulla. Lisäksi tarvitaan
1347yksi Game-tyyppinen parametri, jotta aliohjelmaamme voisi kutsua myös
1348toisesta ohjelmasta. Nämä parametrit riittävät lumiukon piirtämiseen.
1349
1350Kun aliohjelmaa käytetään ohjelmassa, sanotaan, että aliohjelmaa
1351*kutsutaan*. Kutsu tapahtuu kirjoittamalla aliohjelman nimi ja antamalla
1352sille parametrit. Aliohjelmakutsun erottaa metodikutsusta vain se, että
1353metodi liittyy aina tiettyyn olioon. Esimerkiksi pallo-olio p1
1354voitaisiin poistaa pelikentällä kutsumalla metodia Destroy(), eli
1355kirjoittaisimme:
1356
1357``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1358p1.Destroy();
1359```
1360
1361Toisin sanoen metodeja kutsuttaessa täytyy ensin kirjoittaa sen olion
1362nimi, jonka metodia kutsutaan, ja sen jälkeen pisteellä erotettuna
1363kirjoittaa haluttu metodin nimi. Sulkujen sisään tulee luonnollisesti
1364tarvittavat parametrit. Yllä olevan esimerkin Destroy-metodi ei ota
1365vastaan yhtään parametria.
1366
1367Päätetään, että aliohjelman nimi on PiirraLumiukko. Sovitaan myös, että
1368aliohjelman ensimmäinen parametri on tämä peli, johon lumiukko ilmestyy
1369(kirjoitetaan this). Toinen parametri on lumiukon alimman pallon
1370keskipisteen x-koordinaatti ja kolmas parametri lumiukon alimman pallon
1371keskipisteen y-koordinaatti. Tällöin kentälle voitaisiin piirtää
1372lumiukko, jonka alimman pallon keskipiste on (0, Level.Bottom + 200.0),
1373seuraavalla kutsulla:
1374
1375``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1376PiirraLumiukko(this, 0, Level.Bottom + 200.0);
1377```
1378
1379Kutsussa voisi myös ensiksi mainita sen luokan nimen mistä aliohjelma
1380löytyy. Tällä kutsulla aliohjelmaa voisi kutsua myös muista luokista,
1381koska määrittelimme Lumiukot-luokan julkiseksi (public).
1382
1383``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1384Lumiukot.PiirraLumiukko(this, 0, Level.Bottom + 200.0);
1385```
1386
1387Vaikka tämä muoto muistuttaa jo melko paljon metodin kutsua on ero
1388kuitenkin selvä. Metodia kutsuttaessa toimenpide tehdään aina *tietylle
1389oliolle*, kuten p1.Destroy() tuhoaa juuri sen pallon, johon p1-olio
1390viittaa. Pallojahan voi tietenkin olla myös muita erinimisiä (kuten
1391esimerkissämme onkin). Alla olevassa aliohjelmakutsussa kuitenkin
1392käytetään vain luokasta Lumiukot löytyvää PiirraLumiukko-aliohjelmaa.
1393
1394Jos olisimme toteuttaneet jo varsinaisen aliohjelman, piirtäisi Begin
1395meille nyt kaksi lumiukkoa.
1396
1397``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1398/// <summary>
1399/// Kutsutaan PiirraLumiukko-aliohjelmaa
1400/// sopivilla parametreilla.
1401/// </summary>
1402public override void Begin()
1403{
1404 Camera.ZoomToLevel();
1405 Level.Background.Color = Color.Black;
1406
1407 PiirraLumiukko(this, 0, Level.Bottom + 200.0);
1408 PiirraLumiukko(this, 200.0, Level.Bottom + 300.0);
1409}
1410```
1411
1412Koska PiirraLumiukko-aliohjelmaa ei luonnollisesti vielä ole olemassa,
1413ei ohjelmamme vielä toimi. Seuraavaksi meidän täytyy toteuttaa itse
1414aliohjelma, jotta kutsut alkavat toimimaan.
1415
1416Usein ohjelman toteutuksessa on viisasta edetä juuri tässä
1417järjestyksessä: suunnitellaan aliohjelmakutsu ensiksi, kirjoitetaan
1418kutsu sille kuuluvalle paikalle, ja vasta sitten toteutetaan varsinainen
1419aliohjelman kirjoittaminen.
1420
1421Lisätietoja aliohjelmien kutsumisesta löydät kurssin wiki-sivulta:
1422[https://trac.cc.jyu.fi/projects/ohj1/wiki/aliohjelmienKutsuminen](https://trac.cc.jyu.fi/projects/ohj1/wiki/aliohjelmienKutsuminen).
1423
14246.2 Aliohjelman kirjoittaminen
1425------------------------------
1426
1427Ennen varsinaista aliohjelman toiminnallisuuden kirjoittamista täytyy
1428aliohjelmalle tehdä määrittely (kutsutaan myös esittelyksi,
1429declaration). Kirjoitetaan määrittely aliohjelmalle, jonka kutsun jo
1430teimme edellisessä alaluvussa.
1431
1432Lisätään ohjelmaamme aliohjelman runko. Dokumentoidaan aliohjelma myös
1433saman tien.
1434
1435``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1436/// <summary>
1437/// Kutsutaan PiirraLumiukko-aliohjelmaa
1438/// sopivilla parametreilla.
1439/// </summary>
1440public override void Begin()
1441{
1442 Camera.ZoomToLevel();
1443 Level.Background.Color = Color.Black;
1444
1445 PiirraLumiukko(this, 0, Level.Bottom + 200.0);
1446 PiirraLumiukko(this, 200.0, Level.Bottom + 300.0);
1447}
1448
1449/// <summary>
1450/// Aliohjelma piirtää lumiukon
1451/// annettuun paikkaan.
1452/// </summary>
1453/// <param name="peli">Peli, johon lumiukko tehdään.</param>
1454/// <param name="x">Lumiukon alimman pallon x-koordinaatti.</param>
1455/// <param name="y">Lumiukon alimman pallon y-koordinaatti.</param>
1456public static void PiirraLumiukko(Game peli, double x, double y)
1457{
1458}
1459```
1460
1461Alla oleva kuva selvittää aliohjelmakutsun ja aliohjelman määrittelyn
1462sekä vastinparametrien yhteyttä.
1463
1464![\
1465 Kuva 5: Aliohjelmakutsu ja aliohjelman
1466vastinparametrit.](../src/luentomonistecsUusin_htm_m48da2e91.png)
1467
1468\
1469 Aliohjelman toteutuksen ensimmäistä riviä
1470
1471``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1472public static void PiirraLumiukko(Game peli, double x, double y)
1473```
1474
1475sanotaan aliohjelman *otsikoksi* (header) tai *esittelyriviksi*. Otsikon
1476alussa määritellään aliohjelman *näkyvyys* julkiseksi (public). Kun
1477näkyvyys on julkinen, niin aliohjelmaa voidaan kutsua eli käyttää myös
1478muissa luokissa. Aliohjelma määritellään myös staattiseksi (static),
1479sillä jos emme määrittelisi aliohjelmaa staattiseksi, olisi se
1480oikeastaan metodi, eli olion toiminto (ks. luku 8.5). Statttinen
1481aliohjelma pystyy tekemään kaikki toimensa parametreinä tuodun tiedon
1482perusteella.
1483
1484Aliohjelmalle on annettu myös palautusarvoksi void, joka tarkoittaa
1485sitä, että aliohjelma ei palauta mitään arvoa. Aliohjelma voisi
1486nimittäin myös lopettaessaan palauttaa jonkun arvon, jota tarvitsisimme
1487ohjelmassamme. Tällaisista aliohjelmista puhutaan luvussa 9.
1488void-määrityksen jälkeen aliohjelmalle on annettu nimeksi
1489PiirraLumiukko.
1490
1491Huomaa! C\#:ssa aliohjelmat kirjoitetaan tyypillisesti isolla
1492alkukirjaimella.
1493
1494\
1495
1496Huomaa! Aliohjelmien (ja metodien) nimien tulisi olla verbejä tai
1497tekemistä ilmaisevia lauseita, esimerkiksi LuoPallo, Siirry,
1498TormattiinEsteeseen.
1499
1500Aliohjelman nimen jälkeen ilmoitetaan sulkeiden sisässä aliohjelman
1501parametrit. Jokaista parametria ennen on ilmoitettava myös parametrin
1502*tietotyyppi*. Parametrinä annettiin lumiukon alimman pallon x- ja
1503y-koordinaatit. Molempien tietotyyppi on double, joten myös
1504vastinparametrien tyyppien tulee olla double. Annetaan myös nimet
1505kuvaavasti x ja y.
1506
1507Tietotyypeistä voit lukea lisää kohdasta 7.2 ja luvusta 8.
1508
1509Huomaa! Aliohjelman parametrien nimien ei tarvitse olla samoja kuin
1510kutsussa. Niiden nimet kannattaa kuitenkin olla mahdollisimman kuvaavia.
1511
1512\
1513
1514Huomaa! Parametrien tyyppien ei tarvitse olla keskenään samoja, kunhan
1515kukin parametri on yhteensopiva kutsussa olevan vastinparametrin kanssa.
1516Esimerkkejä funktioista löydät kurssin wiki-sivulta:
1517[https://trac.cc.jyu.fi/projects/ohj1/wiki/aliohjelmienKirjoittaminen](https://trac.cc.jyu.fi/projects/ohj1/wiki/aliohjelmienKirjoittaminen).
1518
1519\
1520
1521Aliohjelmakutsulla ja aliohjelman määrittelyllä on siis hyvin vahva
1522yhteys keskenään. Aliohjelmakutsussa annetut tiedot ”sijoitetaan”
1523kullakin kutsukerralla aliohjelman määrittelyrivillä esitellyille
1524vastinparametreille. Toisin sanoen, aliohjelmakutsun yhteydessä tapahtuu
1525väljästi sanottuna seuraavaa.
1526
1527``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1528aliohjelman Game = this;
1529aliohjelman x = 200.0;
1530aliohjelman y = Level.Bottom + 300;
1531```
1532
1533Voimme nyt kokeilla ajaa ohjelmaamme. Se toimii (lähtee käyntiin), mutta
1534ei tietenkään vielä piirrä lumiukkoja, eikä pitäisikään, sillä luomamme
1535aliohjelma on ”tyhjä”. Lisätään aaltosulkujen väliin varsinainen koodi,
1536joka pallojen piirtämiseen tarvitaan.
1537
1538Pieni muutos aikaisempaan versioon kuitenkin tarvitaan. Rivit, joilla
1539pallot lisätään kentälle, muutetaan muotoon
1540
1541``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1542peli.Add(...);
1543```
1544
1545missä pisteiden paikalle tulee pallo-olion muuttujan nimi.
1546
1547``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1548/// <summary>
1549/// Kutsutaan PiirraLumiukko-aliohjelmaa
1550/// sopivilla parametreilla.
1551/// </summary>
1552public override void Begin()
1553{
1554 Camera.ZoomToLevel();
1555 Level.Background.Color = Color.Black;
1556
1557 PiirraLumiukko(this, 0, Level.Bottom + 200.0);
1558 PiirraLumiukko(this, 200.0, Level.Bottom + 300.0);
1559}
1560
1561/// <summary>
1562/// Aliohjelma piirtää lumiukon
1563/// annettuun paikkaan.
1564/// </summary>
1565/// <param name="g">Peli, johon lumiukko tehdään.</param>
1566/// <param name="x">Lumiukon alimman pallon x-koordinaatti.</param>
1567/// <param name="y">Lumiukon alimman pallon y-koordinaatti.</param>
1568public static void PiirraLumiukko(Game peli, double x, double y)
1569{
1570 PhysicsObject p1, p2, p3;
1571 p1 = new PhysicsObject(2 * 100.0, 2 * 100.0, Shape.Circle);
1572 p1.X = x;
1573 p1.Y = y;
1574 peli.Add(p1);
1575
1576 p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
1577 p2.X = x;
1578 p2.Y = p1.Y + 100 + 50;
1579 peli.Add(p2);
1580
1581 p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
1582 p3.X = x;
1583 p3.Y = p2.Y + 50 + 30;
1584 peli.Add(p3);
1585}
1586```
1587
1588Varsinaista aliohjelman toiminnallisuutta kirjoittaessa käytämme nyt
1589parametreille antamiamme nimiä. Alimman ympyrän keskipisteen
1590koordinaatit saamme nyt suoraan parametreista x ja y, mutta muiden
1591ympyröiden keskipisteet meidän täytyy laskea alimman ympyrän
1592koordinaateista. Tämä tapahtuu täysin samalla tavalla kuin edellisessä
1593esimerkissä. Itse asiassa, jos vertaa aliohjelman sisältöä edellisen
1594esimerkin koodiin, on se täysin sama.
1595
1596C\#:ssa on tapana aloittaa aliohjelmien ja metodien nimet isolla
1597kirjaimella ja nimessä esiintyvä jokainen uusi sana alkamaan isolla
1598kirjaimella. Kirjoitustavasta käytetään termiä PascalCasing. Muuttujat
1599kirjoitetaan pienellä alkukirjaimella, ja jokainen seuraava sana isolla
1600alkukirjaimella: esimerkiksi double autonNopeus. Tästä käytetään nimeä
1601camelCasing. Lisää C\#:n nimeämiskäytännöistä voit lukea sivulta
1602
1603[http://msdn.microsoft.com/en-us/library/ms229043.aspx](http://msdn.microsoft.com/en-us/library/ms229043.aspx).
1604
1605Tarkastellaan seuraavaksi mitä aliohjelmakutsussa tapahtuu.
1606
1607``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1608PiirraLumiukko(this, 0, Level.Bottom + 200.0);
1609```
1610
1611Yllä olevalla kutsulla aliohjelman peli-nimiseen muuttujaan sijoitetaan
1612this, eli kyseessä oleva peli, x-nimiseen muuttujaan sijoitetaan arvo 0
1613(liukulukuun voi sijoittaa kokonaislukuarvon) ja aliohjelman muuttujaan
1614y arvo Level.Bottom + 200.0. Voisimme sijoittaa tietenkin minkä tahansa
1615muunkin liukuluvun.
1616
1617Aliohjelmakutsun suorituksessa lasketaan siis ensiksi jokaisen kutsussa
1618olevan lausekkeen arvo ja sitten lasketut arvot sijoitetaan kutsussa
1619olevassa järjestyksessä aliohjelman vastinparametreille. Siksi
1620vastinparametrien pitää olla sijoitusyhteensopivia kutsun lausekkeiden
1621kanssa. Esimerkin kutsussa lausekkeet ovat yksinkertaisia: muuttujan
1622nimi (this), kokonaislukuarvo (0) ja reaalilukuarvo ( Level.Bottom +
1623200.0). Ne voisivat kuitenkin olla kuinka monimutkaisia lausekkeita
1624tahansa, esimerkiksi näin:
1625
1626``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1627PiirraLumiukko(this, 22.7+sin(2.4), 80.1-Math.PI);
1628```
1629
1630\
1631 \
1632
1633*Lause* (statement) ja *lauseke* (expression) ovat eri asia. Lauseke on
1634arvojen, aritmeettisten operaatioiden ja aliohjelmien (tai metodien
1635yhdistelmä), joka evaluoituu tietyksi arvoksi. Lauseke on siis lauseen
1636osa. Seuraava kuva selventää eroa.
1637
1638![\
1639 Kuva 6: Lauseen ja lausekkeen
1640ero](../src/luentomonistecsUusin_htm_m5dfaebb8.png)
1641
1642\
1643 Koska määrittelimme koordinaattien parametrien tyypiksi double,
1644voisimme yhtä hyvin antaa parametreiksi mitä tahansa muitakin
1645desimaalilukuja. Täytyy muistaa, että C\#:ssa desimaalilukuvakioissa
1646käytetään pistettä erottamaan kokonaisosa desimaaliosasta.
1647
1648Kokonaisuudessaan ohjelma näyttää nyt seuraavalta:
1649
1650``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
165101 using Jypeli;
165202
165303
165404 /// @author Antti-Jussi Lakanen, Vesa Lappalainen
165505 /// @version 22.8.2012
165606 ///
165707 /// <summary>
165808 /// Piirretään lumiukkoja ja harjoitellaan aliohjelman käyttöä.
165909 /// </summary>
166010 public class Lumiukot : PhysicsGame
166111 {
166212 /// <summary>
166313 /// Pääohjelmassa laitetaan "peli" käyntiin.
166414 /// </summary>
166515 /// <param name="args">Ei käytössä</param>
166616 public static void Main(string[] args)
166717 {
166818 using (Lumiukot peli = new Lumiukot())
166919 {
167020 peli.Run();
167121 }
167222 }
167323
167424 /// <summary>
167525 /// Kutsutaan PiirraLumiukko-aliohjelmaa
167626 /// sopivilla parametreilla.
167727 /// </summary>
167828 public override void Begin()
167929 {
168030 Camera.ZoomToLevel();
168131 Level.Background.Color = Color.Black;
168232
168333 PiirraLumiukko(this, 0, Level.Bottom + 200.0);
168434 PiirraLumiukko(this, 200.0, Level.Bottom + 300.0);
168535 }
168636
168737 /// <summary>
168838 /// Aliohjelma piirtää lumiukon
168939 /// annettuun paikkaan.
169040 /// </summary>
169141 /// <param name="peli">Peliluokka</param>
169242 /// <param name="x">Lumiukon alimman pallon x-koordinaatti.</param>
169343 /// <param name="y">Lumiukon alimman pallon y-koordinaatti.</param>
169444 public static void PiirraLumiukko(Game peli, double x, double y)
169545 {
169646 PhysicsObject p1, p2, p3;
169747 p1 = new PhysicsObject(2 * 100.0, 2 * 100.0, Shape.Circle);
169848 p1.X = x;
169949 p1.Y = y;
170050 peli.Add(p1);
170151
170252 p2 = new PhysicsObject(2 * 50.0, 2 * 50.0, Shape.Circle);
170353 p2.X = x;
170454 p2.Y = p1.Y + 100 + 50;
170555 peli.Add(p2);
170656
170757 p3 = new PhysicsObject(2 * 30.0, 2 * 30.0, Shape.Circle);
170858 p3.X = x;
170959 p3.Y = p2.Y + 50 + 30;
171060 peli.Add(p3);
171161 }
171262 }
1713```
1714
1715\
1716 \
1717
1718Kutsuttaessa aliohjelmaa hyppää ohjelman suoritus välittömästi
1719parametrien sijoitusten jälkeen kutsuttavan aliohjelman ensimmäiselle
1720riville ja alkaa suorittamaan aliohjelmaa kutsussa määritellyillä
1721parametreilla. Kun päästään aliohjelman koodin loppuun palataan
1722jatkamaan kutsun jälkeisestä seuraavasta lausekkeesta. Esimerkissämme
1723kun ensimmäinen lumiukko on piirretty, palataan tavallaan ensimmäisen
1724kutsun puolipisteeseen ja sitten pääohjelma jatkuu kutsumalla toista
1725lumiukon piirtämistä.
1726
1727Jos nyt haluaisimme piirtää lisää lumiukkoja, lisäisi jokainen uusi
1728lumiukko koodia vain yhden rivin.
1729
1730Huomaa! Aliohjelmien käyttö selkeyttää ohjelmaa ja aliohjelmia kannattaa
1731kirjoittaa, vaikka niitä kutsuttaisiin vain yhden kerran. Hyvää
1732aliohjelmaa voidaan kutsua muustakin käyttöyhteydestä.
1733
17346.3 Aliohjelmien dokumentointi
1735------------------------------
1736
1737Jokaisen aliohjelman tulisi sisältää dokumentaatiokommentti. Aliohjelman
1738dokumentaatiokommentin tulee sisältää ainakin seuraavat asiat: Lyhyt
1739kuvaus aliohjelman toiminnasta, selitys kaikista parametreista sekä
1740selitys mahdollisesta paluuarvosta. Nämä asiat kuvataan tägien avulla
1741seuraavasti:
1742
1743- Dokumentaatiokommentin alkuun laitetaan \<summary\>-tagien väliin
1744 lyhyt ja selkeä kuvaus aliohjelman toiminnasta.
1745
1746- Jokainen parametri selitetään omien \<param\>-tagien väliin ja
1747
1748- paluuarvo \<returns\>-tagien väliin.
1749
1750PiirraLumiukko-aliohjelman dokumentaatiokommentit on edellisessä
1751esimerkissämme riveillä 36-41.
1752
1753\
1754
1755``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
175636 /// <summary>
175737 /// Aliohjelma piirtää lumiukon
175838 /// annettuun paikkaan.
175939 /// </summary>
176040 /// <param name="g">Peliluokka</param>
176141 /// <param name="x">Lumiukon alimman pallon x-koordinaatti.</param>
176242 /// <param name="y">Lumiukon alimman pallon y-koordinaatti.</param>
1763```
1764
1765*Doxygen*-työkalun (ks.
1766[http://en.wikipedia.org/wiki/Doxygen](http://en.wikipedia.org/wiki/Doxygen))
1767tuottama HTML-sivu tästä luokasta näyttäisi nyt seuraavalta:
1768
1769![\
1770 Kuva 7: Osa Lumiukot-luokan
1771dokumentaatiosta](../src/luentomonistecsUusin_htm_5219b95e.png)
1772
1773\
1774 Dokumentaatiossa näkyy kaikki luokan aliohjelmat ja metodit. Huomaa,
1775että Doxygen nimittää sekä aliohjelmia että metodeja jäsenfunktioiksi
1776(member functions). Kuten sanottu, nimitykset vaihtelevat
1777kirjallisuudessa, ja tässä kohtaa käytössä on hieman harvinaisempi
1778nimeämistapa. Kysymys on kuitenkin samasta asiasta, josta me tällä
1779kurssilla käytämme nimeä aliohjelmat ja metodit.
1780
1781Jokaisesta aliohjelmasta ja metodista löytyy lisäksi tarkemmat tiedot
1782Detailed Description -kohdasta. Aliohjelman PiirraLumiukko dokumentaatio
1783parametreineen näkyy kuvan alaosassa.
1784
1785### 6.3.1 Huomautus
1786
1787Kaikki PiirraLumiukko-aliohjelmassa tarvittava tieto välitettiin
1788parametrien avulla, eikä aliohjelman suorituksen aikana tarvittu
1789aliohjelman ulkopuolisia tietoja. Tämä on tyypillistä aliohjelmille, ja
1790usein lisäksi toivottava ominaisuus.
1791
17926.4 Aliohjelmat, metodit ja funktiot
1793------------------------------------
1794
1795Kuten ehkä huomasit, aliohjelmilla ja metodeilla on paljon yhteistä.
1796Monissa kirjoissa nimitetään myös aliohjelmia metodeiksi. Tällöin
1797aliohjelmat erotetaan olioiden metodeista nimittämällä niitä
1798staattisiksi metodeiksi. Tässä monisteessa metodeista puhutaan kuitenkin
1799vain silloin, kun tarkoitetaan olioiden toimintoja. Jypelin
1800dokumentaatiosta tutkit RandomGen-luokan staattisia metodeja, millä
1801voidaan luoda esimerkiksi satunnaisia lukuja. Yksittäinen pallo
1802poistettiin metodilla Destroy, joka on olion toiminto.
1803
1804Aliohjelmista puhutaan tällä kurssilla, koska sitä termiä käytetään
1805monissa muissa ohjelmointikielissä. Tämä kurssi onkin ensisijaisesti
1806ohjelmoinnin kurssi, jossa käytetään C\#-kieltä. Päätavoitteena on siis
1807oppia ohjelmoimaan ja työkaluna meillä sen opettelussa on C\#-kieli.
1808
1809Aliohjelmamme PiirraLumiukko ei palauttanut mitään arvoa. Aliohjelmaa
1810(tai metodia) joka palauttaa jonkun arvon voidaan kutsua myös tarkemmin
1811*funktioksi* (function).
1812
1813Aliohjelmia ja metodeja nimitetään eri tavoin eri kielissä. Esimerkiksi
1814C++-kielessä sekä aliohjelmia että metodeja sanotaan funktioiksi.
1815Metodeita nimitetään C++-kielessä tarkemmin vielä jäsenfunktioiksi,
1816kuten Doxygen teki myös C\#:n tapauksessa.
1817
1818Kerrataan vielä lyhyesti aliohjelman, funktion ja metodin erot.
1819
1820**Aliohjelma**\
1821 Osaohjelma, joka voi tehdä kaikki toimensa käyttäen hyväkseen vain
1822parametrilistassa tuotua tietoa. Paluuarvon tyyppinä on void, jolloin
1823aliohjelma ei palauta mitään arvoa.
1824
1825**Funktio\
1826**Aliohjelma, joka palauttaa jonkin tuloksen, esimerkiksi kahden luvun
1827keskiarvon. Tämän määritelmän mukaan funktiossa on aina return-lause
1828jonka perässä on lauseke, esimerkiksi return (a+b)/2.0; Puhtaassa
1829aliohjelmassakin (ks. edellinen kohta) voi olla return-lause, mutta sen
1830perässä ei ole lauseketta.
1831
1832**Metodi\
1833**Aliohjelma, joka tarvitsee tehtävän suorittamiseksi kohteena olevan
1834olion omia tietoja. Näitä käytetään tällä kurssilla, mutta ei tehdä
1835alkupään esimerkeissä itse. Lopullisessa pelissä voi tulla tehtäväksi
1836myös metodeja, jotka tarvitsevat peliluokan-olion tietoja toimintansa
1837toteuttamiseen. Joku voi myös mahdollisesti tehdä vaikka uuden
1838aseluokan, jolle kirjoitetaan omia metodeja.
1839
1840Metodi voi myös funktion tapaan palauttaa arvon tai aliohjelman tapaan
1841olla palauttamatta. Emme erottele tätä enää eri nimillä.
1842
18437. Muuttujat
1844============
1845
1846Muuttujat (variable) toimivat ohjelmassa tietovarastoina erilaisille
1847asioille. Muuttuja on kuin pieni laatikko, johon voidaan varastoida
1848asioita, esimerkiksi lukuja, sanoja, tietoa ohjelman käyttäjästä ja
1849paljon muuta. Ilman muuttujia järkevä tiedon käsittely olisi oikeastaan
1850mahdotonta. Olemme jo ohimennen käyttäneetkin muuttujia, esimerkiksi
1851Lumiukko-esimerkissä teimme PhysicsObject-tyyppisiä muuttujia p1, p2 ja
1852p3. Vastaavasti Lumiukko-aliohjelman parametrit (Game peli, double x,
1853double y) ovat myös muuttujia: Game-tyyppinen oliomuuttuja peli, sekä
1854double-alkeistietotyyppiset muuttujat x ja y.
1855
1856Termi *muuttuja* on lainattu ohjelmointiin matematiikasta, mutta niitä
1857ei tule kuitenkaan sekoittaa keskenään - muuttuja matematiikassa ja
1858muuttuja ohjelmoinnissa tarkoittavat hieman eri asioita. Tulet
1859huomaamaan tämän seuraavien kappaleiden aikana.
1860
1861Muuttujien arvot tallennetaan keskusmuistiin tai rekistereihin, mutta
1862ohjelmointikielissä voimme antaa kullekin muuttujalle nimen
1863(identifier), jotta muuttujan arvon käsittely olisi helpompaa. Muuttujan
1864nimi onkin ohjelmointikielten helpotus, sillä näin ohjelmoijan ei
1865tarvitse tietää tarvitsemansa tiedon keskusmuisti- tai
1866rekisteriosoitetta, vaan riittää muistaa itse nimeämänsä muuttujan nimi.
1867[VES]
1868
18697.1 Muuttujan määrittely
1870------------------------
1871
1872Kun matemaatikko sanoo, että ”n on yhtäsuuri kuin 1”, tarkoittaa se,
1873että tuo termi (eli muuttuja) n on jollain käsittämättömällä tavalla
1874sama kuin luku 1. Matematiikassa muuttujia voidaan esitellä tällä
1875tavalla ”häthätää”.
1876
1877Ohjelmoijan on kuitenkin tehtävä vastaava asia hieman tarkemmin.
1878C\#-kielessä tämä tapahtuisi kirjoittamalla seuraavasti:
1879
1880``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1881int n;
1882n = 1;
1883```
1884
1885Ensimmäinen rivi tarkoittaa väljästi sanottuna, että ”lohkaise pieni
1886pala - johon mahtuu int-kokoinen arvo - säilytystilaa tietokoneen
1887muistista, ja käytä siitä jatkossa nimeä n. Toisella rivillä
1888julistetaan, että ”talleta arvo 1 muuttujaan, jonka nimi on n, siten
1889korvaten sen, mitä kyseisessä säilytystilassa mahdollisesti jo on”.
1890
1891Mikä sitten on tuo edellisen esimerkin int?
1892
1893C\#:ssa jokaisella muuttujalla täytyy olla *tietotyyppi* (usein myös
1894lyhyesti *tyyppi*). Tietotyyppi on määriteltävä, jotta ohjelma tietäisi,
1895millaista tietoa muuttujaan tullaan tallentamaan. Toisaalta tietotyyppi
1896on määriteltävä siksi, että ohjelma osaa varata muistista sopivan
1897kokoisen lohkareen muuttujan sisältämää tietoa varten. Esimerkiksi
1898int-tyypin tapauksessa tilantarve olisi 32 bittiä (4 tavua), byte-tyypin
1899tapauksessa 8 bittiä (1 tavu) ja double-tyypin 64 bittiä (8 tavua).
1900Muuttuja määritellään (declare) kirjoittamalla ensiksi tietotyyppi ja
1901sen perään muuttujan nimi. Muuttujan nimet aloitetaan C\#ssa pienellä
1902kirjaimella, jonka jälkeen jokainen uusi sana alkaa aina isolla
1903kirjaimella. Kuten aiemmin mainittiin, tämä nimeämistapa on nimeltään
1904camelCasing.
1905
1906``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1907muuttujanTietotyyppi muuttujanNimi;
1908```
1909
1910Tuo mainitsemamme int on siis tietotyyppi, ja int-tyyppiseen muuttujaan
1911voi tallentaa kokonaislukuja. Muuttujaan n voimme laittaa lukuja 1, 2,
19123, samoin 0, -1, -2, ja niin edelleen, mutta emme lukua 0.1 tai sanaa
1913”Moi”.
1914
1915Henkilön iän voisimme tallentaa seuraavaan muuttujaan:
1916
1917``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1918int henkilonIka;
1919```
1920
1921Huomaa, että tässä emme aseta muuttujalle mitään arvoa, vain
1922määrittelemme muuttujan int-tyyppiseksi ja annamme sille nimen.
1923
1924Samantyyppisiä muuttujia voidaan määritellä kerralla useampia
1925erottamalla muuttujien nimet pilkulla. Tietotyyppiä double käytetään,
1926kun halutaan tallentaa desimaalilukuja.
1927
1928``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1929double paino, pituus;
1930```
1931
1932Määrittely onnistuu toki myös erikseen.
1933
1934``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
1935double paino;
1936double pituus;
1937```
1938
19397.2 Alkeistietotyypit
1940---------------------
1941
1942C\#:n tietotyypit voidaan jakaa alkeistietotyyppeihin (primitive types)
1943ja oliotietotyyppeihin (reference types). Oliotietotyyppeihin kuuluu
1944muun muassa käyttämämme PhysicsObject-tyyppi, jota pallot p1 jne.
1945olivat, sekä merkkijonojen tallennukseen tarkoitettu String-olio.
1946Oliotyyppejä käsitellään myöhemmin luvussa 8.
1947
1948Eri tietotyypit vaativat eri määrän kapasiteettia tietokoneen muistista.
1949Vaikka nykyajan koneissa on paljon muistia, on hyvin tärkeää valita
1950oikean tyyppinen muuttuja kuhunkin tilanteeseen. Suurissa ohjelmissa
1951ongelma korostuu hyvin nopeasti käytettäessä muuttujia, jotka kuluttavat
1952tilanteeseen nähden kohtuuttoman paljon muistikapasiteettia. C\#:n
1953alkeistietotyypit on lueteltu alla.
1954
1955Taulukko 1: C\#:n alkeistietotyypit koon mukaan järjestettynä.
1956
1957C\#-merkki
1958
1959Koko
1960
1961Selitys
1962
1963Arvoalue
1964
1965bool
1966
19671 bitti
1968
1969kaksiarvoinen tietotyyppi
1970
1971true tai false
1972
1973sbyte
1974
19758 bittiä
1976
1977yksi tavu
1978
1979-128..127
1980
1981byte
1982
19838 bittiä
1984
1985yksi tavu (etumerkitön)
1986
19870..255
1988
1989char
1990
199116 bittiä
1992
1993yksi merkki
1994
1995kaikki merkit
1996
1997short
1998
199916 bittiä
2000
2001pieni kokonaisluku
2002
2003-32,768..32,767
2004
2005ushort
2006
200716 bittiä
2008
2009pieni kokonaisluku (etumerkitön)
2010
20110..65,535
2012
2013int
2014
201532 bittiä
2016
2017kokonaisluku
2018
2019-2,147,483,648..\
2020 2,147,483,647
2021
2022uint
2023
202432 bittiä
2025
2026kokonaisluku (etumerkitön)
2027
20280..4,294,967,295
2029
2030float
2031
203232 bittiä
2033
2034liukuluku
2035
2036noin 7 desimaalin tarkkuus,
2037
2038±1.5 × 10^-45^.. ±3.4 × 10^38^
2039
2040long
2041
204264 bittiä
2043
2044iso kokonaisluku
2045
2046-2^63^..2^63^-1
2047
2048ulong
2049
205064 bittiä
2051
2052iso kokonaisluku (etumerkitön)
2053
20540..\
2055 18,446,744,073,709,615
2056
2057double
2058
205964 bittiä
2060
2061tarkka liukuluku
2062
2063noin 15 desimaalin tarkkuus,
2064
2065±5.0 × 10^-324^.. ±1.7 × 10^308^
2066
2067decimal
2068
2069128 bittiä
2070
2071erittäin tarkka liukuluku
2072
2073Noin 28 luvun tarkkuus
2074
2075\
2076
2077\
2078
2079\
2080
2081\
2082
2083Tässä monisteessa suositellaan, että desimaalilukujen talletukseen
2084käytettäväksi aina double-tietotyyppiä (jossain tapauksissa jopa
2085decimal-tyyppiä), vaikka monessa paikassa float-tietotyyppiä
2086käytetäänkin. Tämä johtuu siitä, että liukuluvut, joina desimaaliluvut
2087tietokoneessa käsitellään, ovat harvoin tarkkoja arvoja tietokoneessa.
2088Itse asiassa ne ovat tarkkoja vain kun ne esittävät jotakin kahden
2089potenssin kombinaatiota, kuten esimerkiksi 2.0, 7.0, 0.5 tai 0.375.
2090
2091Useimmiten liukuluvut ovat pelkkiä approksimaatioita oikeasta
2092reaaliluvusta. Esimerkiksi lukua 0.1 ei pystytä tietokoneessa esittämään
2093biteillä tarkasti. Tällöin laskujen määrän kasvaessa lukujen epätarkkuus
2094vain lisääntyy. Tämän takia onkin turvallisempaa käyttää aina
2095double-tietotyyppiä, koska se suuremman bittimääränsä takia pystyy
2096tallettamaan enemmän merkitseviä desimaaleja.
2097
2098Tietyissä sovelluksissa, joissa mahdollisimman suuri tarkkuus on
2099välttämätön (kuten pankki- tai nanotason fysiikkasovellukset), on
2100suositeltavaa käyttää korkeimpaa mahdollista tarkkuutta tarjoavaa
2101decimal-tyyppiä. Reaalilukujen esityksestä tietokoneessa puhutaan lisää
2102kohdassa [26.6](#o246Liukuluku_floatingpoint). [VES][KOS]
2103
21047.3 Arvon asettaminen muuttujaan
2105--------------------------------
2106
2107Muuttujaan asetetaan arvo sijoitusoperaattorilla (assignment operator)
2108"=". Lauseita, joilla asetetaan muuttujille arvoja sanotaan
2109sijoituslauseiksi (assignment statement). On tärkeää huomata, että
2110sijoitus tapahtuu aina oikealta vasemmalle: sijoitettava on
2111yhtäsuuruusmerkin oikealla puolella ja kohde merkin vasemmalla puolella.
2112
2113``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2114x = 20.0;
2115henkilonIka = 23;
2116paino = 80.5;
2117pituus = 183.5;
2118```
2119
2120Muuttujaan voi asettaa arvon myös jo määrittelyn yhteydessä.
2121
2122``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2123bool onkoKalastaja = true;
2124char merkki = 't';
2125int kalojenLkm = 0;
2126double luku1 = 0, luku2 = 0, luku3 = 0;
2127```
2128
2129Muuttuja täytyy olla määritelty tietyn tyyppiseksi ennen kuin siihen voi
2130asettaa arvoa. Muuttujaan voi asettaa vain määrittelyssä annetun
2131tietotyypin mukaisia arvoja tai sen kanssa *sijoitusyhteensopivia*
2132arvoja. Esimerkiksi liukulukutyyppeihin (float ja double) voi sijoittaa
2133myös kokonaislukutyyppisiä arvoja, sillä kokonaisluvut on reaalilukujen
2134osajoukko. Alla sijoitamme arvon 4 muuttujaan nimeltä luku2, ja
2135kolmannella rivillä luku2-muuttujan sisältämän arvon (4) muuttujaan,
2136jonka nimi on luku1.
2137
2138``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2139double luku1;
2140int luku2 = 4;
2141luku1 = luku2;
2142```
2143
2144Toisinpäin tämä ei onnistu: double-tyyppistä arvoa ei voi sijoittaa
2145int-tyyppiseen muuttujaan. Alla oleva koodi ei kääntyisi:
2146
2147``` {.huonoesimerkki-western lang="zxx" xml:lang="zxx"}
2148//TÄMÄ KOODI EI KÄÄNNY!
2149int luku1;
2150double luku2 = 4.0;
2151luku1 = luku2;
2152```
2153
2154Kun decimal-tyyppinen muuttuja alustetaan jollain luvulla, tulee luvun
2155perään (ennen puolipistettä) laittaa m (tai M)-merkki. Samoin
2156float-tyyppisten muuttujien alustuksessa perään laitetaan f (tai
2157F)-merkki.
2158
2159``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2160decimal tilinSaldo = 3498.98m;
2161float lampotila = -4.8f;
2162```
2163
2164Huomaa, että char-tyyppiseen muuttujaan sijoitetaan arvo laittamalla
2165merkki heittomerkkien väliin, esimerkiksi näin.
2166
2167``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2168char ekaKirjain = 'k';
2169```
2170
2171Näin sen erottaa myöhemmin käsiteltävästä String-tyyppiseen muuttujaan
2172sijoittamisesta, jossa sijoitettava merkkijono laitetaan lainausmerkkien
2173väliin, esimerkiksi seuraavasti.
2174
2175``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2176String omaNimi = "Antti-Jussi";
2177```
2178
2179Sijoituslause voi sisältää myös monimutkaisiakin lausekkeita,
2180esimerkiksi aritmeettisia operaatioita:
2181
2182``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2183double numeroidenKeskiarvo = (2 + 4 + 1 + 5 + 3 + 2) / 6.0;
2184```
2185
2186Sijoituslause voi sisältää myös muuttujia.
2187
2188``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2189double huoneenPituus = 540.0;
2190double huoneenLeveys = huoneenPituus;
2191double huoneenAla = huoneenPituus * huoneenLeveys;
2192```
2193
2194Eli sijoitettava voi olla mikä tahansa lauseke, joka tuottaa muuttujalle
2195kelpaavan arvon.
2196
2197C\#:ssa täytyy aina asettaa joku arvo muuttujaan *ennen* sen
2198käyttämistä. Kääntäjä ei käännä koodia, jossa käytetään muuttujaa jolle
2199ei ole asetettu arvoa. Alla oleva ohjelma ei siis kääntyisi.
2200
2201``` {.huonoesimerkki-western lang="zxx" xml:lang="zxx"}
2202// TÄMÄ OHJELMA EI KÄÄNNY
2203public class Esimerkki
2204{
2205 public static void Main(string[] args)
2206 {
2207 int ika;
2208 System.Console.WriteLine(ika);
2209 }
2210}
2211```
2212
2213Virheilmoitus näyttää tältä:
2214
2215``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2216Esimerkki.cs(4,40): error CS0165: Use of unassigned local variable
2217 'ika'
2218```
2219
2220Kääntäjä kertoo, että ika-nimistä muuttuja yritetään käyttää, vaikka
2221sille ei ole osoitettu mitään arvoa. Tämä ei ole sallittua, joten
2222ohjelman kääntämisyritys päättyy tähän.
2223
22247.4 Muuttujan nimeäminen
2225------------------------
2226
2227Muuttujan nimen täytyy olla siihen tallennettavaa tietoa kuvaava.
2228Yleensä pelkkä yksi kirjain on huono nimi muuttujalle, sillä se harvoin
2229kuvaa kovin hyvin muuttujaa. Kuvaava muuttujan nimi selkeyttää koodia ja
2230vähentää kommentoimisen tarvetta. Lyhyt muuttujan nimi ei ole
2231itseisarvo. Vielä parikymmentä vuotta sitten se saattoi olla sitä, koska
2232se nopeutti koodin kirjoittamista. Nykyaikaisia kehitysympäristöjä
2233käytettäessä tämä ei enää pidä paikkaansa, sillä editorit osaavat
2234täydentää muuttujan nimen samalla kun koodia kirjoitetaan, joten niitä
2235ei käytännössä koskaan tarvitse kirjoittaa kokonaan, paitsi tietysti
2236ensimmäisen kerran.
2237
2238Yksikirjaimisia muuttujien nimiäkin voi perustellusti käyttää, jos
2239niillä on esimerkiksi jo matematiikasta tai fysiikasta ennestään tuttu
2240merkitys. Nimet x ja y ovat hyviä kuvaamaan koordinaatteja. Nimi l (eng.
2241length) viittaa pituuteen ja r (eng. radius) säteeseen. Fysikaalisessa
2242ohjelmassa s voi hyvin kuvata matkaa.
2243
2244Huomaa! Muuttujan nimi ei voi C\#:ssa alkaa numerolla.
2245
2246C\#:n koodauskäytänteiden mukaan muuttujan nimi alkaa pienellä
2247kirjaimella ja jos muuttujan nimi koostuu useammasta sanasta aloitetaan
2248uusi sana aina isolla kirjaimella kuten alla.
2249
2250``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2251int polkupyoranRenkaanKoko;
2252```
2253
2254C\#:ssa muuttujan nimi voi sisältää ääkkösiä, mutta niiden käyttö ei
2255suositella, koska siirtyminen koodistosta toiseen aiheuttaa usein
2256ylimääräisiä ongelmia.
2257
2258*Koodisto =* Määrittelee jokaiselle *merkistön* merkille yksikäsitteisen
2259koodinumeron. Merkin numeerinen esitys on usein välttämätön
2260tietokoneissa. Merkistö määrittelee joukon merkkejä ja niille nimen,
2261numeron ja jonkinnäköisen muodon kuvauksen. Merkistöllä ja koodistolla
2262tarkoitetaan usein samaa asiaa, kuitenkin esimerkiksi Unicode-merkistö
2263sisältää useita eri koodaus tapoja (UTF-8, UTF-16, UTF-32). Koodisto on
2264siis se merkistön osa, joka määrittelee merkille numeerisen koodiarvon.
2265Koodistoissa syntyy ongelmia yleensä silloin, kun siirrytään jostain
2266skandimerkkejä (ä,ö,å, ...) sisältävästä koodistosta seitsemänbittiseen
2267ASCII-koodistoon, joka ei tue skandeja. ASCII-koodistosta puhutaan lisää
2268luvussa [27](#o25_ASCIIkoodi).
2269
2270### 7.4.1 C\#:n varatut sanat
2271
2272Muuttujan nimi ei saa olla mikään ohjelmointikielen varatuista sanoista,
2273eli sanoista joilla on C\#:ssa joku muu merkitys.
2274
2275Taulukko 2: C\#:n varatut sanat.
2276
2277 ---------- ---------- ----------- ------------ -----------
2278 abstract do in protected true
2279 as double int public try
2280 base else interface readonly typeof
2281 bool enum internal ref uint
2282 break event is return ulong
2283 byte explicit lock sbyte unchecked
2284 case extern long sealed unsafe
2285 catch false namespace short ushort
2286 char finally new sizeof using
2287 checked fixed null stackalloc virtual
2288 class float object static void
2289 const for operator string volatile
2290 continue foreach out struct while
2291 decimal goto override switch
2292 default if params this
2293 delegate implicit private throw
2294 ---------- ---------- ----------- ------------ -----------
2295
2296\
2297 \
2298
2299\
2300 \
2301
23027.5 Muuttujien näkyvyys
2303-----------------------
2304
2305Muuttujaa voi käyttää (lukea ja asettaa arvoja) vain siinä lohkossa,
2306missä se on määritelty. Muuttujan määrittelyn täytyy aina olla ennen
2307(koodissa ylempänä), kun sitä ensimmäisen kerran käytetään. Jos muuttuja
2308on käytettävissä sanotaan, että muuttuja *näkyy*. Aliohjelman sisällä
2309määritelty muuttuja ei siis näy muissa aliohjelmissa.
2310
2311Luokan sisällä muuttuja voidaan määritellä myös niin, että se näkyy
2312kaikkialla, siis kaikille aliohjelmille. Kun muuttuja on näkyvissä
2313kaikille ohjelman osille, sanotaan sitä *globaaliksi muuttujaksi*
2314(global variable). Globaaleja muuttujia tulee välttää aina kun
2315mahdollista.
2316
2317Lisätietoa muuttujien näkyvyydestä löydät wikistä osoitteessa
2318
2319[https://trac.cc.jyu.fi/projects/ohj1/wiki/MuuttujienNakyvyys](https://trac.cc.jyu.fi/projects/ohj1/wiki/MuuttujienNakyvyys).
2320
23217.6 Vakiot
2322----------
2323
2324> One man's constant is another man's variable. -Alan Perlis
2325
2326Muuttujien lisäksi ohjelmointikielissä voidaan määritellä vakioita
2327(constant). Vakioiden arvoa ei voi muuttaa määrittelyn jälkeen. C\#:ssa
2328vakio määritellään muuten kuten muuttuja, mutta muuttujan tyypin eteen
2329kirjoitetaan lisämääre const.
2330
2331``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2332const int KUUKAUSIEN_LKM = 12;
2333```
2334
2335Tällä kurssilla vakiot kirjoitetaan suuraakkosin siten, että sanat
2336erotetaan alaviivalla (\_). Näin ne erottaa helposti muuttujien nimistä,
2337jotka alkavat pienellä kirjaimella. Muitakin kirjoitustapoja on,
2338esimerkiksi Pascal Casing on toinen yleisesti käytetty vakioiden
2339kirjoitusohje.
2340
23417.7 Operaattorit
2342----------------
2343
2344Usein meidän täytyy tallentaa muuttujiin erilaisten laskutoimitusten
2345tuloksia. C\#:ssa laskutoimituksia voidaan tehdä aritmeettisilla
2346operaatioilla (arithmetic operation), joista mainittiin jo kun teimme
2347lumiukkoesimerkkiä. Ohjelmassa olevia aritmeettisia laskutoimituksia
2348sanotaan aritmeettisiksi lausekkeiksi (arithmetic expression).
2349
2350C\#:ssa on myös vertailuoperaattoreita (comparison operators), loogisia
2351operaattoreita, bittikohtaisia operaattoreita (bitwise operators),
2352arvonmuunto-operaattoreita (shortcut operators), sijoitusoperaattori =,
2353is-operaattori sekä ehto-operaattori ?. Tässä luvussa käsitellään näistä
2354tärkeimmät.
2355
2356### 7.7.1 Aritmeettiset operaatiot
2357
2358C\#:ssa peruslaskutoimituksia suoritetaan aritmeettisilla operaatiolla,
2359joista + ja - tulivatkin esille aikaisemmissa esimerkeissä.
2360Aritmeettisia operaattoreita on viisi.
2361
2362Taulukko 3: Aritmeettiset operaatiot.
2363
2364Operaat-\
2365 tori
2366
2367Toiminto
2368
2369Esimerkki
2370
2371+
2372
2373yhteenlasku
2374
2375System.Console.WriteLine(1+2); // tulostaa 3
2376
2377-
2378
2379vähennyslasku
2380
2381System.Console.WriteLine(1-2); // tulostaa -1
2382
2383\*
2384
2385kertolasku
2386
2387System.Console.WriteLine(2\*3); // tulostaa 6
2388
2389/
2390
2391jakolasku
2392
2393System.Console.WriteLine(6 / 2); // tulostaa 3
2394
2395System.Console.WriteLine(7 / 2); // Huom! 3
2396
2397System.Console.WriteLine(7 / 2.0); // 3.5
2398
2399System.Console.WriteLine(7.0 / 2); // 3.5
2400
2401%
2402
2403jakojäännös (modulo)
2404
2405System.Console.WriteLine(18 % 7); // tulostaa 4
2406
2407### 7.7.2 Vertailuoperaattorit
2408
2409Vertailuoperaattoreiden avulla verrataan muuttujien arvoja keskenään.
2410Vertailuoperaattorit palauttavat totuusarvon (true tai false).
2411Vertailuoperaattoreita on kuusi. Lisää vertailuoperaattoreista luvussa
241213.
2413
2414### 7.7.3 Arvonmuunto-operaattorit
2415
2416Arvonmuunto-operaattoreiden avulla laskutoimitukset voidaan esittää
2417tiiviimmässä muodossa: esimerkiksi x++; (4 merkkiä) tarkoittaa samaa
2418asiaa kuin x = x+1; (6 merkkiä). Niiden avulla voidaan myös alustaa
2419muuttujia.
2420
2421\
2422 \
2423
2424Taulukko 4: Arvonmuunto-operaattorit.
2425
2426Ope-raattori
2427
2428Toiminto
2429
2430Esimerkki
2431
2432++
2433
2434Lisäysoperaattori. Lisää muuttujan arvoa yhdellä.
2435
2436int luku = 0;
2437
2438\
2439
2440System.Console.WriteLine(luku++); //tulostaa 0
2441
2442System.Console.WriteLine(luku++); //tulostaa 1
2443
2444System.Console.WriteLine(luku); //tulostaa 2
2445
2446System.Console.WriteLine(++luku); //tulostaa 3
2447
2448--
2449
2450Vähennysoperaattori. Vähentää muuttujan arvoa yhdellä.
2451
2452int luku = 5;
2453
2454System.Console.WriteLine(luku--); //tulostaa 5
2455
2456System.Console.WriteLine(luku--); //tulostaa 4
2457
2458System.Console.WriteLine(luku); //tulostaa 3
2459
2460System.Console.WriteLine(--luku); //tulostaa 2
2461
2462System.Console.WriteLine(luku); //tulostaa 2
2463
2464+=
2465
2466Lisäys-operaatio.
2467
2468int luku = 0;
2469
2470luku += 2; //luku muuttujan arvo on 2
2471
2472luku += 3; //luku muuttujan arvo on 5
2473
2474luku += -1; //luku muuttujan arvo on 4
2475
2476-=
2477
2478Vähennys-operaatio
2479
2480int luku = 0;
2481
2482luku -= 2; // luku muuttujan arvo on -2
2483
2484luku -= 1 // luku muuttujan arvon -3
2485
2486\*=
2487
2488Kertolasku-operaatio
2489
2490int luku = 1;
2491
2492luku \*= 3; // luku-muuttujan arvo on 3
2493
2494luku \*= 2; //luku-muuttujan arvo on 6
2495
2496/=
2497
2498Jakolasku-operaatio
2499
2500double luku = 27;
2501
2502luku /= 3; //luku-muuttujan arvo on 9
2503
2504luku /= 2.0; //luku-muuttujan arvo on 4.5
2505
2506%=
2507
2508Jakojäännös-operaatio
2509
2510int luku = 9;
2511
2512luku %= 5; //luku-muuttujan arvo on 4
2513
2514luku %=2; //luku-muuttujan arvo on 0
2515
2516\
2517
2518\
2519
2520\
2521
2522Lisäysoperaattoria (++) ja vähennysoperaattoria (--) voidaan käyttää,
2523ennen tai jälkeen muuttujan. Käytettäessä ennen muuttujaa, arvoa
2524muutetaan ensin ja mahdollinen toiminto esimerkiksi tulostus, tehdään
2525vasta sen jälkeen. Jos operaattori sen sijaan on muuttujan perässä,
2526toiminto tehdään ensiksi ja arvoa muutetaan vasta sen jälkeen.
2527
2528Huomaa! Arvonmuunto-operaattorit ovat ns. sivuvaikutuksellisia
2529operaattoreita. Toisin sanoen, operaatio muuttaa muuttujan arvoa toisin
2530kuin esimerkiksi aritmeettiset operaatiot. Seuraava esimerkki
2531havainnollistaa asiaa.
2532
2533\
2534 \
2535
2536``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2537int luku1 = 5;
2538int luku2 = 5;
2539System.Console.WriteLine(++luku1); // tulostaa 6;
2540System.Console.WriteLine(luku2 + 1 ); // tulostaa 6;
2541System.Console.WriteLine(luku1); // 6
2542System.Console.WriteLine(luku2); // 5
2543```
2544
2545### 7.7.4 Aritmeettisten operaatioiden suoritusjärjestys
2546
2547Aritmeettisten operaatioiden suoritusjärjestys on vastaava kuin
2548matematiikan laskujärjestys. Kerto- ja jakolaskut suoritetaan ennen
2549yhteen- ja vähennyslaskua. Lisäksi sulkeiden sisällä olevat lausekkeet
2550suoritetaan ensin.
2551
2552``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2553System.Console.WriteLine(5 + 3 * 4 - 2); //tulostaa 15
2554System.Console.WriteLine((5 + 3) * (4 - 2)); //tulostaa 16
2555```
2556
25577.8 Huomautuksia
2558----------------
2559
2560### 7.8.1 Kokonaisluvun tallentaminen liukulukumuuttujaan
2561
2562Kun yritetään tallentaa kokonaislukujen jakolaskun tulosta
2563liukulukutyyppiseen (float tai double) muuttujaan, voi tulos tallettua
2564kokonaislukuna, jos jakaja ja jaettava ovat molemmat ilmoitettu ilman
2565desimaaliosaa.
2566
2567``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2568double laskunTulos = 5 / 2;
2569System.Console.WriteLine(laskunTulos); // tulostaa 2
2570```
2571
2572Jos kuitenkin vähintään yksi jakolaskun luvuista on desimaalimuodossa,
2573niin laskun tulos tallentuu muuttujaan oikein.
2574
2575``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2576double laskunTulos = 5 / 2.0;
2577System.Console.WriteLine(laskunTulos); // tulostaa 2.5
2578```
2579
2580Liukuluvuilla laskettaessa kannattaa pitää desimaalimuodossa myös luvut,
2581joilla ei ole desimaaliosaa, eli ilmoittaa esimerkiksi luku 5 muodossa
25825.0.
2583
2584Kokonaisluvuilla laskettaessa kannattaa huomioida seuraava:
2585
2586``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2587int laskunTulos = 5 / 4;
2588System.Console.WriteLine(laskunTulos); // tulostaa 1
2589
2590laskunTulos = 5 / 6;
2591System.Console.WriteLine(laskunTulos); // tulostaa 0
2592
2593laskunTulos = 7 / 3;
2594System.Console.WriteLine(laskunTulos); // tulostaa 2
2595```
2596
2597Kokonaisluvuilla laskettaessa lukuja ei siis pyöristetä lähimpään
2598kokonaislukuun, vaan desimaaliosa menee C\#:n jakolaskuissa ikään kuin
2599"hukkaan".
2600
2601### 7.8.2 Lisäys- ja vähennysoperaattoreista
2602
2603On neljä tapaa kasvattaa luvun arvoa yhdellä.
2604
2605``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2606++a;
2607a++; // idiomi
2608a += 1;
2609a = a + 1; // huonoin muutettavuuden ja kirjoittamisen kannalta
2610```
2611
2612Ohjelmoinnissa *idiomilla* tarkoitetaan tapaa jolla asia yleensä
2613kannattaa tehdä. Näistä a++ on ohjelmoinnissa vakiintunut tapa ja
2614(yleensä) suositeltavin, siis idiomi. Kuitenkin, jos lukua a pitäisikin
2615kasvattaa (tai vähentää) kahdella tai kolmella, ei tämä tapa enää
2616toimisi. Seuraavassa esimerkissä tarkastellaan eri tapoja kahdella
2617vähentämiseksi. Siihen on kolme vaihtoehtoista tapaa.
2618
2619``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2620a -= 2;
2621a += -2; // lisättävä luku voisi olla muuttuja. Luku voi olla myös negatiivinen
2622a = a - 2;
2623```
2624
2625Tässä tapauksessa += -operaattorin käyttö olisi suositeltavinta, sillä
2626lisättävä luku voi olla positiivinen tai negatiivinen (tai nolla), joten
2627+= -operaattori ei tässä rajoita sitä, millaisia lukuja a-muuttujaan
2628voidaan lisätä.
2629
26307.9 Esimerkki: Painoindeksi
2631---------------------------
2632
2633Tehdään ohjelma joka laskee painoindeksin. Painoindeksi lasketaan
2634jakamalla paino (kg) pituuden (m) neliöllä, eli kaavalla
2635
2636``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2637paino / (pituus * pituus)
2638```
2639
2640C\#:lla painoindeksi saadaan siis laskettua seuraavasti.
2641
2642``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2643/// @author Antti-Jussi Lakanen
2644/// @version 22.8.2012
2645///
2646/// <summary>
2647/// Ohjelma, joka laskee painoindeksin
2648/// pituuden (m) ja painon (kg) perusteella.
2649/// </summary>
2650public class Painoindeksi
2651{
2652 /// <summary>
2653 /// Pääohjelma, jossa painoindeksi tulostetaan ruudulle.
2654 /// </summary>
2655 public static void Main()
2656 {
2657 double pituus = 1.83;
2658 double paino = 75.0;
2659 double painoindeksi = paino / (pituus*pituus);
2660 System.Console.WriteLine(painoindeksi);
2661 }
2662}
2663```
2664
2665\
2666 \
2667
26688. Oliotietotyypit
2669==================
2670
2671C\#:n alkeistietotyypit antavat melko rajoittuneet puitteet
2672ohjelmointiin. Niillä pystytään tallentamaan ainoastaan lukuja ja
2673yksittäisiä kirjaimia. Vähänkin monimutkaisemmissa ohjelmissa tarvitaan
2674kehittyneempiä rakenteita tiedon tallennukseen. C\#:ssa, Javassa ja
2675muissa oliokielissä tällaisen rakenteen tarjoavat oliot. C\#:ssa jo
2676merkkijonokin (String) toteutetaan oliona.
2677
26788.1 Mitä oliot ovat?
2679--------------------
2680
2681Olio (object) on ”tietorakenne”, jolla pyritään ohjelmoinnissa kuvaamaan
2682reaalimaailman ilmiöitä. Luokkapohjaisissa kielissä (kuten C\#, Java ja
2683C++) olion rakenteen ja käyttäytymisen määrittelee luokka, joka kuvaa
2684olion attribuutit ja metodit. Attribuutit ovat olion ominaisuuksia ja
2685metodit olion toimintoja. Olion sanotaan olevan luokan *ilmentymä*.
2686Yhdestä luokasta voi siis luoda useita olioita, joilla on samat metodit
2687ja attribuutit. Attribuutit voivat saada samasta luokasta luoduilla
2688olioilla eri arvoja. Attribuuttien arvot muodostavat olion tilan. Huomaa
2689kuitenkin, että vaikka oliolla olisi sama tila, sen *identiteetti* on
2690eri. Esimerkiksi, kaksi täsmälleen samannäköistä palloa voi olla samassa
2691paikassa (näyttää yhdeltä pallolta), mutta todellisuudessa ne ovat kaksi
2692eri palloa.
2693
2694Olioita voi joko tehdä itse tai käyttää jostain kirjastosta löytyviä
2695valmiita olioita. Omien olioluokkien tekeminen ei kuulu vielä
2696Ohjelmointi 1 -kurssin asioihin, mutta käyttäminen kyllä. Tarkastellaan
2697seuraavaksi luokan ja olion suhdetta, sekä kuinka oliota käytetään.
2698
2699Luokan ja olion suhdetta voisi kuvata seuraavalla esimerkillä. Olkoon
2700luentosalissa useita ihmisiä. Kaikki luentosalissa olijat ovat ihmisiä.
2701Heillä on tietyt samat ominaisuudet, jotka ovat kaikilla ihmisillä,
2702kuten pää, kaksi silmää ja muitakin ruumiinosia. Kuitenkin jokainen
2703salissa olija on erilainen ihmisen ilmentymä, eli jokaisella oliolla on
2704oma identiteetti - eiväthän he ole yksi ja sama vaan heitä on useita.
2705Eri ihmisillä voi olla erilainen tukka ja eriväriset silmät ja oma
2706puhetyyli. Lisäksi ihmiset voivat olla eri pituisia, painoisia jne.
2707Luentosalissa olevat identtiset kaksosetkin olisivat eri ilmentymiä
2708ihmisestä. Jos Ihminen olisi luokka, niin kaikki luentosalissa olijat
2709olisivat Ihminen-luokan ilmentymiä eli Ihminen-olioita. Tukka, silmät,
2710pituus ja paino olisivat sitten olion ominaisuuksia eli attribuutteja.
2711Ihmisellä voisi olla lisäksi joitain toimintoja eli metodeja kuten Syo,
2712MeneToihin, Opiskele jne. Tarkastellaan seuraavaksi hieman todellisempaa
2713esimerkkiä olioista.
2714
2715Oletetaan, että suunnittelisimme yritykselle palkanmaksujärjestelmää.
2716Siihen tarvittaisiin muun muassa Tyontekija-luokka. Tyontekija-luokalla
2717täytyisi olla ainakin seuraavat attribuutit: nimi, tehtava, osasto,
2718palkka. Luokalla täytyisi olla myös ainakin seuraavat metodit:
2719MaksaPalkka, MuutaTehtava, MuutaOsasto, MuutaPalkka. Jokainen työntekijä
2720olisi nyt omanlaisensa Tyontekija-luokan ilmentymä eli olio.
2721
27228.2 Olion luominen
2723------------------
2724
2725``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2726Tyontekija teppo = new Tyontekija("Teppo Tunari", "Projektipäällikkö", "Tutkimusosasto", 5000);
2727```
2728
2729Olioviite määritellään kirjoittamalla ensiksi sen luokan nimi, josta
2730olio luodaan. Seuraavaksi kirjoitetaan nimi, jonka haluamme oliolle
2731antaa. Nimen jälkeen tulee yhtäsuuruusmerkki, jonka jälkeen oliota
2732luotaessa kirjoitetaan sana new ilmoittamaan, että luodaan uusi olio.
2733Tämä new-operaattori varaa tilan tietokoneen muistista oliota varten.
2734
2735Seuraavaksi kirjoitetaan luokan nimi uudelleen, jonka perään
2736kirjoitetaan sulkuihin mahdolliset olion luontiin liittyvät parametrit.
2737Parametrit riippuvat siitä kuinka luokan *konstruktori* (constructor,
2738muodostaja) on toteutettu. Konstruktori on metodi, joka suoritetaan aina
2739kun uusi olio luodaan. Valmiita luokkia käyttääkseen ei tarvitse
2740kuitenkaan tietää konstruktorin toteutuksesta, vaan tarvittavat
2741parametrit selviävät aina luokan dokumentaatiosta. Yleisessä muodossa
2742uusi olio luodaan alla olevalla tavalla.
2743
2744``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2745Luokka olionNimi = new Luokka(parametri1, parametri2,..., parametriN);
2746```
2747
2748Jos olio ei vaadi luomisen yhteydessä parametreja, kirjoitetaan silloin
2749tyhjä sulkupari.
2750
2751Ennen kuin oliolle on varattu tila tietokoneen muistista
2752new-operaattorilla, ei sitä voi käyttää. Ennen new-operaattorin käyttöä
2753olion arvo on null, joka tarkoittaa, että olio on käyttökelvoton,
2754”mitätön”. Tällaisen olion käyttö aiheuttaa virheilmoituksen. Olio
2755voidaan myös tarkoituksellisesti merkitä käyttökelvottomaksi asettamalla
2756olionNimi = null.
2757
2758Uusi Tyontekija-olio voitaisiin luoda esimerkiksi seuraavasti.
2759Parametrit riippuisivat nyt siitä kuinka olemme toteuttaneet
2760Tyontekija-luokan konstruktorin. Tässä tapauksessa annamme nyt
2761parametrina oliolle kaikki attribuutit.
2762
2763``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2764Tyontekija akuAnkka = new Tyontekija("Aku Ankka", "Johtaja", "Osasto3", 3000);
2765```
2766
2767Monisteen alussa loimme lumiukkoja piirrettäessä PhysicsObject-luokan
2768olion seuraavasti.
2769
2770``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2771PhysicsObject p1 = new PhysicsObject(2 * 100.0, 2 * 100.0, Shape.Circle);
2772```
2773
2774Itse asiassa oliomuuttuja on C\#:ssa ainoastaan *viite* varsinaiseen
2775olioon. Siksi niitä kutsutaankin usein myös *viitemuuttujiksi.*
2776Viitemuuttujat eroavat oleellisesti alkeistietotyyppisistä muuttujista.
2777
27788.3 Oliotietotyyppien ja alkeistietotyyppien ero
2779------------------------------------------------
2780
2781C\#:ssa on kahden mallisia rakenteita, joihin tietoja voidaan tallentaa.
2782Tapauksesta riippuen tiedot tallennetaan joko *alkeistietotyyppeihin*
2783tai *oliotietotyyppeihin*. Oliotietotyypit eroavat alkeistietotyypeistä
2784siinä, että ne ovat *viitteitä* tiettyyn olioon, ja siksi niitä
2785kutsutaan myös nimellä viitetyypit tai viitemuuttujat.
2786
2787- Alkeistietotyypit säilyttävät sisältämänsä tiedon yhdessä paikassa
2788 tietokoneen muistissa (nimeltään *pino*).
2789
2790- Viitetyypit sisältävät viitteen johonkin toiseen paikkaan muistissa
2791 (kutsutaan nimellä *keko*), missä varsinainen data sijaitsee.
2792 Viittaus olioon sijaitsee kuitenkin pinossa.
2793
2794Yleensä meidän ei tarvitse olla kovin huolissamme siitä käytämmekö
2795alkeistietotyyppiä (kuten int, double tai char) vai oliotyyppiä (kuten
2796String). Yleisesti ottaen tärkein ero on siinä, että alkeistietotyyppien
2797tulee (tiettyjä poikkeuksia lukuun ottamatta) aina sisältää jokin arvo,
2798mutta oliotietotyypit voivat olla null-arvoisia (eli ”ei-minkään”
2799arvoisia). Jäljempänä esimerkkejä alkeistietotyyppien ja viitetyyppien
2800eroista.
2801
2802Samaan olioon voi viitata useampi muuttuja. Vertaa alla olevia
2803koodinpätkiä.
2804
2805``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2806int luku1 = 10;
2807int luku2 = luku1;
2808luku1 = 0;
2809Console.WriteLine(luku2); //tulostaa 10
2810```
2811
2812Yllä oleva tulostaa ”10” niin kuin pitääkin. Muuttujan luku2 arvo ei
2813siis muutu, vaikka asetamme kolmannella rivillä muuttujaan luku1 arvon
28140. Tämä johtuu siitä, että toisella rivillä asetamme muuttujaan luku2
2815muuttujan luku1 arvon, emmekä viitettä muuttujaan luku1.
2816Oliotietotyyppisten muuttujien kanssa asia on toinen. Vertaa yllä olevaa
2817esimerkkiä seuraavaan:
2818
2819``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2820PhysicsObject p1 = new PhysicsObject(2*100.0, 2*100.0, Shape.Circle);
2821Add(p1);
2822p1.X = -50;
2823
2824PhysicsObject p2 = p1;
2825p2.X = 100;
2826```
2827
2828Yllä oleva koodi piirtää seuraavan kuvan:
2829
2830![\
2831 Kuva 8: Molemmat muuttujat, p1 ja p2, liikuttelevat samaa ympyrää.
2832Lopputuloksena ympyrä seisoo pisteessä
2833x=100.](../src/luentomonistecsUusin_htm_m3838408a.png)
2834
2835\
2836 Nopeasti voisi olettaa, että ikkunassamme näkyisi nyt vain kaksi
2837samanlaista ympyrää eri paikoissa. Näin ei kuitenkaan ole, vaan molemmat
2838PhysicsObject-oliot viittaavat samaan ympyrään, jonka säde on 50. Tämä
2839johtuu siitä, että muuttujat p1 ja p2 ovat olioviitteitä, jotka
2840viittaavat (ts. osoittavat) samaan olioon.
2841
2842``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2843PhysicsObject p2 = p1;
2844```
2845
2846Toisin sanoen yllä olevalla rivillä ei luoda uutta PhysicsObject-oliota,
2847vaan ainoastaan uusi olioviite, joka viittaa nyt samaan olioon kuin p1.
2848
2849![\
2850 Kuva 9: Sekä p1 että p2 viittaavat samaan
2851olioon.](../src/luentomonistecsUusin_htm_75ff594f.png)
2852
2853\
2854 \
2855
2856*Oliomuuttuja =* Viite todelliseen olioon. Samaan olioon voi olla
2857useitakin viitteitä.
2858
2859Viitteitä käsitellään tarkemmin luvussa 14.
2860
28618.4 Metodin kutsuminen
2862----------------------
2863
2864Jokaisella tietystä luokasta luodulla oliolla on käytössä kaikki tämän
2865luokan julkiset metodit. Metodikutsussa käsketään oliota tekemään
2866jotain. Voisimme esimerkiksi käskeä PhysicsObject-oliota liikkumaan, tai
2867Tyontekija-oliota muuttamaan palkkaansa.
2868
2869Olion metodeita kutsutaan kirjoittamalla ensiksi olion nimi, piste ja
2870kutsuttavan metodin nimi. Metodin mahdolliset parametrit laitetaan
2871sulkeiden sisään ja erotetaan toisistaan pilkulla. Jos metodi ei vaadi
2872parametreja, täytyy sulut silti kirjoittaa, niiden sisälle ei vaan tule
2873mitään. Yleisessä muodossa metodikutsu on seuraava:
2874
2875``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2876olionNimi.MetodinNimi(parametri1,parametri2,...parametriN);
2877```
2878
2879Voisimme nyt esimerkiksi muuttaa akuAnkka-olion palkkaa alla olevalla
2880tavalla.
2881
2882``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2883akuAnkka.MuutaPalkka(3500);
2884```
2885
2886Tai laittaa p1-olion (oletetaan että p1 on PhysicsObject-olio)
2887liikkeelle käyttäen Hit-metodia.
2888
2889``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2890p1.Hit(new Vector(1000.0, 500.0));
2891```
2892
2893String-luokasta löytyy esimerkiksi Contains-metodi, joka palauttaa arvon
2894True tai False. Parametrina Contains-metodille annetaan merkkijono, ja
2895metodi etsii oliosta antamaamme merkkijonoa vastaavia ilmentymiä. Jos
2896olio sisältää merkkijonon (yhden tai useamman kerran) palautetaan True.
2897Muutoin palautetaan False. Alla esimerkki.
2898
2899``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2900String lause = "Pekka meni kauppaan";
2901Console.WriteLine(lause.Contains("eni")); // Tulostaa True
2902```
2903
29048.5 Metodin ja aliohjelman ero
2905------------------------------
2906
2907Aliohjelma esitellään static-tyyppiseksi, mikäli aliohjelma ei käytä
2908mitään muita tietoja kuin parametreinä tuodut tiedot. Esimerkiksi
2909luvussa 20.4.2 on seuraava aliohjelma.
2910
2911``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2912private void KuunteleLiiketta(AnalogState hiirenTila)
2913{
2914 pallo.X = Mouse.PositionOnWorld.X;
2915 pallo.Y = Mouse.PositionOnWorld.Y;
2916
2917 Vector hiirenLiike = hiirenTila.MouseMovement;
2918}
2919```
2920
2921Tässä tarvitaan hiiren tilan lisäksi pelioliossa esitellyn pallon
2922tietoja, joten enää ei ole kyse stattisesta aliohjelmasta ja siksi
2923static-sana jätetään pois. Metodi sen sijaan pystyy käyttämään *olion*
2924omia "ominaisuuksia", attribuutteja, metodeja ja ns. ominaisuus-kenttiä
2925(property fields).
2926
29278.6 Olion tuhoaminen ja roskienkeruu
2928------------------------------------
2929
2930Kun olioon ei enää viittaa yhtään muuttujaa (olioviitettä), täytyy olion
2931käyttämät muistipaikat vapauttaa muuhun käyttöön. Oliot poistetaan
2932muistista puhdistusoperaation avulla. Tästä huolehtii C\#:n
2933automaattinen roskienkeruu (garbage collection). Kun olioon ei ole enää
2934viitteitä, se merkitään poistettavaksi ja aina tietyin väliajoin
2935*puhdistusoperaatio* (kutsutaan usein myös nimellä roskienkerääjä,
2936garbage collector) vapauttaa merkittyjen olioiden muistipaikat.
2937
2938Kaikissa ohjelmointikielissä näin ei ole (esim. alkuperäinen C++), vaan
2939muistin vapauttamisesta ja olioiden tuhoamisesta tulee useimmiten
2940huolehtia itse. Näissä kielissä on yleensä destruktori (destructor =
2941hajottaja), joka suoritetaan aina kun olio tuhotaan. Itse
2942kirjoitettavasta destruktorista on tapana kutsua olion elinaikanaan
2943luomien olioiden tuhoamista tai muiden resurssien vapauttamista. Vertaa
2944konstruktoriin, joka suoritettiin kun olio luodaan. Haastavaksi näiden
2945kielien yhteydessä tuleekin se, että joissakin tapauksissa olioiden
2946elinkaari on automaattista ja joissakin ei. Siksi muistivuodot ovat
2947erittäin yleisiä aloittelevilla C++ -ohjelmoijilla.
2948
2949Yleensä C\#-ohjelmoijan ei tarvitse huolehtia muistin vapauttamisesta,
2950mutta on tiettyjä tilanteita, joissa voidaan itse joutua poistamaan
2951oliot. Yksi esimerkki tällaisesta tilanteesta on tiedostojen käsittely:
2952Jos olio on avannut tiedoston, olisi viimeistään ennen olion tuhoamista
2953järkevää sulkea tiedosto. Tällöin samassa yhteydessä olion tuhottavaksi
2954merkitsemisen kanssa suoritettaisiin myös tiedoston sulkeminen. Tämä
2955tehdään esittelemällä *hajotin* (destructor), joka on luokan metodi ja
2956jonka tehtävänä on tyhjentää olio kaikesta sen sisältämästä tiedosta
2957sekä vapauttaa sen sisältämät rakenteet, kuten kytkökset avoinna oleviin
2958resursseihin (esim tiedostoon, tosin yleensä tiedostoa ei ole hyvä pitää
2959avoinna niin kauan aikaa kuin jonkin olion elinkaari voi olla).
2960
29618.7 Olioluokkien dokumentaatio
2962------------------------------
2963
2964Luokan dokumentaatio sisältää tiedot luokasta, luokan konstruktoreista
2965ja metodeista. Luokkien dokumentaatioissa on yleensä linkkejä
2966esimerkkeihin, kuten myös String-luokan tapauksessa. Tutustutaan nyt
2967tarkemmin String-luokan dokumentaatioon. String-luokan dokumentaatio
2968löytyy sivulta
2969[http://msdn.microsoft.com/en-us/library/system.string.aspx](http://msdn.microsoft.com/en-us/library/system.string.aspx),
2970ja lista *jäsenistä* eli käytössä olevista konstruktoreista,
2971attribuuteista (fields), ominaisuuksista (property) ja metodeista
2972sivulta
2973[http://msdn.microsoft.com/en-us/library/system.string\_members.aspx](http://msdn.microsoft.com/en-us/library/system.string_members.aspx).
2974
2975Olemme kiinnostuneita tässä vaiheessa kohdista String Constructor ja
2976String Methods (sivun vasemmassa osassa hierarkiapuussa). Klikkaa
2977kohdasta String Constructor saadaksesi lisätietoa luokan
2978konstruktoreista tai String Methods saadaksesi tietoja käytössä olevista
2979metodeista.
2980
2981### 8.7.1 Konstruktorit
2982
2983Avaa luokan String sivu String Constructor. Tämä kohta sisältää tiedot
2984kaikista luokan konstruktoreista. Konstruktoreita voi olla useita,
2985kunhan niiden parametrit eroavat toisistaan. Jokaisella konstruktorilla
2986on oma sivu, ja sivulla kunkin ohjelmointikielen kohdalla oma versionsa,
2987sillä .NET Framework käsittää useita ohjelmointikieliä. Me olemme
2988luonnollisesti tässä vaiheessa kiinnostuneita vain C\#-kielisistä
2989versioista.
2990
2991Kunkin konstruktorin kohdalla on lyhyesti kerrottu mitä se tekee, ja sen
2992jälkeen minkä tyyppisiä ja montako parametria konstruktori ottaa
2993vastaan. Kaikista konstruktoreista saa lisätietoa klikkaamalla
2994konstruktorin esittelyriviä. Esimerkiksi linkki
2995
2996``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
2997[C#] public String(char[]);
2998```
2999
3000vie [sivulle](http://msdn.microsoft.com/en-us/library/ttyxaek9.aspx)
3001([http://msdn.microsoft.com/en-us/library/ttyxaek9.aspx](http://msdn.microsoft.com/en-us/library/ttyxaek9.aspx))
3002jossa konstruktorista public String(char[]) kerrotaan lisätietoja ja
3003annetaan käyttöesimerkkejä.
3004
3005![\
3006 Kuva 10: Tiedot luokan konstruktoreista löytyvät MSDN-dokumentaatioissa
3007Constructor-kohdasta.](../src/luentomonistecsUusin_htm_1b70689e.png)
3008
3009\
3010 \
3011 \
3012
3013Huomaa, että monet String-luokan konstruktoreista on merkitty
3014unsafe-merkinnällä, jolloin niitä ei tulisi käyttää omassa koodissa.
3015Tällaiset konstruktorit on tarkoitettu ainoastaan järjestelmien
3016keskinäiseen viestintään.
3017
3018Tässä vaiheessa voi olla vielä hankalaa ymmärtää kaikkien konstruktorien
3019merkitystä, sillä ne sisältävät tietotyyppejä joita emme ole vielä
3020käsitelleet. Esimerkiksi tietotyypin perässä olevat hakasulkeet (esim.
3021int[]) tarkoittavat että kyseessä on *taulukko*. Taulukoita käsitellään
3022lisää luvussa 15.
3023
3024String-luokan olio on C\#:n ehkä yleisin olio, ja on itse asiassa
3025kokoelma (taulukko) perättäisiä yksittäisiä char-tyyppisiä merkkejä. Se
3026voidaan luoda seuraavasti.
3027
3028``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3029String nimi = new string(new char [] {'J', 'a', 'n', 'n', 'e'});
3030System.Console.WriteLine(nimi); // Tulostaa Janne
3031```
3032
3033Näin kirjoittaminen on tietenkin usein melko vaivalloista. String-luokan
3034olio voidaan kuitenkin poikkeuksellisesti luoda myös
3035alkeistietotyyppisten muuttujien määrittelyä muistuttavalla tavalla.
3036Alla oleva oleva lause on vastaava kuin edellisessä kohdassa, mutta
3037lyhyempi kirjoittaa.
3038
3039``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3040String nimi = "Janne";
3041```
3042
3043Huomaa, että merkkijonon ympärille tulee lainausmerkit. Näppäimistöltä
3044lainausmerkit saadaan näppäinyhdistelmällä
3045`Shift+2`{.terminaali-western}. Vastaavasti merkkijono voitaisiin
3046kuitenkin alustaa myös muilla String-luokan konstruktoreilla, joita on
3047pitkä lista.
3048
3049Jos taas tutkimme PhysicsObject-luokan dokumentaatiota (löytyy
3050osoitteesta
3051[http://kurssit.it.jyu.fi/npo/material/latest/documentation/html/](http://kurssit.it.jyu.fi/npo/material/latest/documentation/html/)
3052→ Luokat → PhysicsObject), löydämme useita eri konstruktoria (ks. kohta
3053*Julkiset jäsenfunktiot*, jotka alkavat sanalla PhysicsObject).
3054Konstruktoreista järjestyksessä toinen saa parametrina kaksi lukua ja
3055muodon. Tätä konstruktoria käytimme jo lumiukkoesimerkissä.
3056
3057![\
3058 Kuva 11: Jypeli-kirjaston luokan konstruktorit löytyvät Julkiset
3059jäsenfunktiot -otsikon
3060alta.](../src/luentomonistecsUusin_htm_74f89f25.png)
3061
3062\
3063 Voisimme kuitenkin olla antamatta muotoa (ensimmäinen konstruktori) ja
3064määritellä muodon vasta myöhemmin fysiikkaolionShape-ominaisuuden
3065avulla.
3066
3067### 8.7.2 Harjoitus
3068
3069Tutki muita konstruktoreja. Mitä niistä selviää dokumentaation
3070perusteella? Mikä on oletusmuoto?
3071
3072### 8.7.3 Metodit
3073
3074Kohta
3075[Methods](http://msdn.microsoft.com/en-us/library/system.string_methods.aspx)
3076([http://msdn.microsoft.com/en-us/library/system.string\_methods.aspx](http://msdn.microsoft.com/en-us/library/system.string_methods.aspx))
3077sisältää tiedot kaikista luokan metodeista. Jokaisella metodilla on
3078taulukossa oma rivi, ja rivillä lyhyt kuvaus, mitä metodi tekee.
3079Klikattuasi jotain metodia saat siitä tarkemmat tiedot. Tällä sivulla
3080kerrotaan mm. minkä tyyppisen parametrin metodi ottaa, ja minkä
3081tyyppisen arvon metodi palauttaa. Esimerkiksi String-luokassa
3082käyttämämme ToUpper-metodi, joka siis palauttaa String-tyyppisen arvon.
3083
3084### 8.7.4 Huomautus: Luokkien dokumentaatioiden googlettaminen
3085
3086Huomaa, että kun haet luokkien dokumentaatioita hakukoneilla, saattavat
3087tulokset viitata .NET Frameworkin vanhempiin versioihin (esimerkiksi 1.0
3088tai 2.0). Kirjoitushetkellä uusin .NET Framework-versio on 4, ja onkin
3089syytä varmistua että löytämäsi dokumentaatio koskee juuri oikeaa
3090versiota. Voit esimerkiksi käyttää hakutermissä versionumeroa tähän
3091tapaan: ”c\# string documentation .net 4”. Versionumeron näkee otsikon
3092alapuolella. Voit halutessasi vaihtaa johonkin toiseen versioon
3093klikkaamalla Other Versions -pudotusvalikkoa.
3094
30958.8 Tyyppimuunnokset
3096--------------------
3097
3098C\#:ssa yhteen muuttujaan voi tallentaa vain yhtä tyyppiä. Tämän takia
3099meidän täytyy joskus muuttaa esimerkiksi String-tyyppinen muuttuja
3100int-tyyppiseksi tai double-tyyppinen muuttuja int-tyyppiseksi ja niin
3101edelleen. Kun muuttujan tyyppi vaihdetaan toiseksi, sanotaan sitä
3102tyyppimuunnokseksi (cast, taitype cast).
3103
3104Kaikilla alkeistietotyypeillä sekä C\#:n oliotyypeillä on
3105ToString-metodi, jolla olio voidaan muuttaa merkkijonoksi. Alla
3106esimerkki int-luvun muuttamisesta merkkijonoksi.
3107
3108``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3109// kokonaisluku merkkijonoksi
3110int kokonaisluku = 24;
3111String intMerkkijonona = kokonaisluku.ToString();
3112
3113// liukuluku merkkijonoksi
3114double liukuluku = 0.562;
3115String doubleMerkkijonona = liukuluku.ToString();
3116```
3117
3118Merkkijonon muuttaminen alkeistietotyypiksi onnistuu sen sijaan
3119jokaiselle alkeistietotyypille tehdystä luokasta löytyvällä metodilla.
3120Alkeistietotyypithän eivät ole olioita, joten niillä ei ole metodeita.
3121C\#:sta löytyy kuitenkin jokaista alkeistietotyyppiä vastaava *rakenne*
3122(struct), joista löytyy alkeistietotyyppien käsittelyyn hyödyllisiä
3123metodeita. Rakenteet sijaitsevat System-nimiavaruudessa, ja tästä syystä
3124ohjelman alussa tarvitaan lause
3125
3126``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3127using System;
3128```
3129
3130Alkeistietotyyppejä vastaavat rakenteet löytyy seuraavasta taulukosta.
3131
3132Taulukko 5: Alkeistietotyypit ja niitä vastaavat rakenteet.
3133
3134Alkeistieto-tyyppi
3135
3136Rakenne
3137
3138bool
3139
3140[Boolean](http://msdn.microsoft.com/en-us/library/system.boolean.aspx)
3141
3142byte
3143
3144[Byte](http://msdn.microsoft.com/en-us/library/system.byte.aspx)
3145
3146char
3147
3148[Char](http://msdn.microsoft.com/en-us/library/system.char.aspx)
3149
3150short
3151
3152[Int16](http://msdn.microsoft.com/en-us/library/system.int16.aspx)
3153
3154int
3155
3156[Int32](http://msdn.microsoft.com/en-us/library/system.int32.aspx)
3157
3158long
3159
3160[Int64](http://msdn.microsoft.com/en-us/library/system.int64.aspx)
3161
3162ulong
3163
3164[UInt64](http://msdn.microsoft.com/en-us/library/system.uint64.aspx)
3165
3166float
3167
3168[Single](http://msdn.microsoft.com/en-us/library/system.single.aspx)
3169
3170double
3171
3172[Double](http://msdn.microsoft.com/en-us/library/system.double.aspx)
3173
3174\
3175
3176\
3177
3178\
3179 Huomaa, että rakenteen ja alkeistietotyypin nimet ovat C\#:ssa
3180synonyymejä. Seuraavat rivit tuottavat saman lopputuloksen (mikäli
3181System-nimiavaruus on otettu käyttöön using-lauseella).
3182
3183``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3184int luku1 = 5;
3185Int32 luku2 = 5;
3186```
3187
3188Vastaavasti kaikki rakenteiden metodit ovat käytössä, kirjoittipa
3189alkeistietotyypin tai rakenteen nimen. Tästä esimerkki seuraavaksi.
3190
3191Merkkijonon (String) muuttaminen int-tyypiksi onnistuu C\#:n
3192int.Parse-funktiolla seuraavasti.
3193
3194``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3195String luku1 = "24";
3196int luku2 = int.Parse(luku1);
3197```
3198
3199Tarkasti sanottuna Parse-funktio luo parametrina saamansa merkkijonon
3200perusteella uuden int-tyyppisen tiedon, joka talletetaan muuttujaan
3201luku2.
3202
3203Jos luvun parsiminen (jäsentäminen, muuttaminen) ei onnistu, aiheuttaa
3204se niin sanotun *poikkeuksen*. double-luvun parsiminen onnistuu
3205vastaavasti Double-rakenteesta (iso D-kirjain) löytyvällä
3206Parse-funktiolla.
3207
3208``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3209String luku3 = "2.45";
3210double luku4 = Double.Parse(luku3);
3211```
3212
3213\
3214 \
3215
32169. Aliohjelman paluuarvo
3217========================
3218
3219Aliohjelmat-luvussa tekemämme Lumiukko-aliohjelma ei palauttanut mitään
3220arvoa. Usein on kuitenkin hyödyllistä, että lopettaessaan aliohjelma
3221palauttaa jotain tietoa ohjelman suorituksesta. Mitä hyötyä olisi
3222esimerkiksi aliohjelmasta, joka laskee kahden luvun keskiarvon, jos emme
3223koskaan saisi tietää mikä niiden lukujen keskiarvo on? Voisimmehan me
3224tietenkin tulostaa luvun keskiarvon suoraan aliohjelmassa, mutta lähes
3225aina on järkevämpää palauttaa tulos ”kysyjälle” paluuarvona. Tällöin
3226aliohjelmaa voidaan käyttää myös tilanteessa, jossa keskiarvoa ei haluta
3227tulostaa, vaan sitä tarvitaan johonkin muuhun laskentaan. Paluuarvon
3228palauttaminen tapahtuu return-lauseella, ja return-lause lopettaa aina
3229aliohjelman suorittamisen (eli palataan takaisin kutsuvaan ohjelman
3230osaan).
3231
3232Toteutetaan nyt aliohjelma, joka laskee kahden kokonaisluvun keskiarvon
3233ja palauttaa tuloksen paluuarvona.
3234
3235``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3236public static double Keskiarvo(int a, int b)
3237{
3238 double keskiarvo;
3239 keskiarvo = (a + b) / 2.0; // Huom 2.0 auttaa, että tulos on reaaliluku
3240 return keskiarvo;
3241}
3242```
3243
3244Ensimmäisellä rivillä määritellään jälleen julkinen ja staattinen
3245aliohjelma. Lumiukko-esimerkissä static-sanan jälkeen luki void, joka
3246tarkoitti, että aliohjelma ei palauttanut mitään arvoa. Koska nyt
3247haluamme, että aliohjelma palauttaa parametrina saamiensa
3248kokonaislukujen keskiarvon, niin meidän täytyy kirjoittaa paluuarvon
3249tyyppi void-sanan tilalle static-sanan jälkeen. Koska kahden
3250kokonaisluvun keskiarvo voi olla myös desimaaliluku, niin paluuarvon
3251tyyppi on double. Sulkujen sisällä ilmoitetaan jälleen parametrit. Nyt
3252parametreina on kaksi kokonaislukua a ja b. Toisella rivillä
3253määritellään reaalilukumuuttuja keskiarvo. Kolmannella rivillä lasketaan
3254parametrien a ja b summa ja jaetaan se kahdella muuttujaan keskiarvo.
3255Neljännellä rivillä palautetaan keskiarvo-muuttujan arvo.
3256
3257Aliohjelmaa voitaisiin nyt käyttää pääohjelmassa esimerkiksi alla
3258olevalla tavalla.
3259
3260``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3261double keskiarvo;
3262keskiarvo = Keskiarvo(3, 4);
3263Console.WriteLine("Keskiarvo = " + keskiarvo);
3264```
3265
3266Tai lyhyemmin kirjoitettuna:
3267
3268``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3269Console.WriteLine("Keskiarvo = " + Keskiarvo(3, 4));
3270```
3271
3272Koska Keskiarvo-aliohjelma palauttaa aina double-tyyppisen liukuluvun,
3273voidaan kutsua käyttää kuten mitä tahansa double-tyyppistä arvoa. Se
3274voidaan esimerkiksi tulostaa tai tallentaa muuttujaan.
3275
3276Itse asiassa koko Keskiarvo-aliohjelman voisi kirjoittaa lyhyemmin
3277muodossa:
3278
3279``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3280public static double Keskiarvo(int a, int b)
3281{
3282 double keskiarvo = (a + b) / 2.0;
3283 return keskiarvo;
3284}
3285```
3286
3287Yksinkertaisimmillaan Keskiarvo-aliohjelman voisi kirjoittaa jopa alla
3288olevalla tavalla.
3289
3290``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3291public static double Keskiarvo(int a, int b)
3292{
3293 return (a + b) / 2.0;
3294}
3295```
3296
3297Kaikki yllä olevat tavat ovat oikein, eikä voi sanoa mikä tapa on paras.
3298Joskus "välivaiheiden" kirjoittaminen selkeyttää koodia, mutta
3299Keskiarvo-aliohjelman tapauksessa viimeisin tapa on selkein ja lyhin.
3300
3301Aliohjelmassa voi olla myös useita return-lauseita. Tästä esimerkki
3302kohdassa: 13.5.1.
3303
3304Aliohjelma ei kuitenkaan voi palauttaa kerralla suoranaisesti useita
3305arvoja. Toki voidaan palauttaa esimerkiksi taulukko, jossa sitten on
3306monia arvoja. Toinen keino olisi tehdä olio, joka sisältäisi useita
3307arvoja ja palautettaisiin. C\#:ssa on olemassa kolmaskin keino on
3308olemassa, jota ei käsitellä tällä kurssilla: ref- ja out-parametrit,
3309katso
3310
3311[http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx](http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx).
3312
3313Metodeita ja aliohjelmia, jotka ottavat vastaan parametreja palauttavat
3314arvon sanotaan joskus myös *funktioiksi*. Nimitys ei ole hullumpi, jos
3315vertaa Keskiarvo-aliohjelmaa vaikkapa matematiikan funktioon f(x, y) =
3316(x + y) / 2. Funktiolla ei lisäksi saisi olla sivuvaikutuksia, kuten
3317esimerkiksi tulostamista tai globaalien muuttujien muuttamista.
3318
3319Mitä eroa on tämän
3320
3321``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3322double tulos = Keskiarvo(5, 2); // funktio Keskiarvo laskisi kahden luvun keskiarvon
3323Console.WriteLine(tulos); //tulostaa 3.5
3324Console.WriteLine(tulos); //tulostaa 3.5
3325```
3326
3327ja tämän
3328
3329``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3330Console.WriteLine(Keskiarvo(5, 2)); //tämäkin tulostaa 3.5
3331Console.WriteLine(Keskiarvo(5, 2)); //tämäkin tulostaa 3.5
3332```
3333
3334koodin suorituksessa?
3335
3336Ensimmäisessä lukujen 5 ja 2 keskiarvo lasketaan vain kertaalleen, jonka
3337jälkeen tulos tallennetaan muuttujaan. Tulostuksessa käytetään sitten
3338tallessa olevaa laskun tulosta.
3339
3340Jälkimmäisessä versiossa lukujen 5 ja 2 keskiarvo lasketaan tulostuksen
3341yhteydessä. Keskiarvo lasketaan siis kahteen kertaan. Vaikka alemmassa
3342tavassa säästetään yksi koodirivi, kulutetaan siinä turhaan tietokoneen
3343resursseja laskemalla sama lasku kahteen kertaan. Tässä tapauksessa
3344tällä ei ole juurikaan merkitystä, sillä Keskarvo-aliohjelman suoritus
3345ei juurikaan rasita nykyaikaisia tietokoneita. Kannattaa kuitenkin
3346opetella tapa, ettei ohjelmassa tehtäisi *mitään* turhia suorituksia.
3347
33489.1 Harjoitus
3349-------------
3350
3351Muuttujat-luvun lopussa tehtiin ohjelma, joka laski painoindeksin. Tee
3352ohjelmasta uusi versio, jossa painoindeksin laskeminen tehdään
3353aliohjelmassa. Aliohjelma saa siis parametreina pituuden ja painon ja
3354palauttaa painoindeksin.
3355
335610. Visual Studio 2010
3357======================
3358
3359Vaikka ohjelmakoodia voi kirjoittaa pelkällä editorillakin, ohjelmien
3360koon kasvaessa alkaa kaipaamaan työvälineiltä hieman enemmän
3361ominaisuuksia. Peruseditoreja enemmän ominaisuuksia tarjoavat
3362sovelluskehittimet eli IDE:t (Integrated Development Environment).
3363C\#:lle tehtyjä ilmaisia sovelluskehittimiä ovat muun muassa
3364
3365- Visual Studio 2010 Express -tuoteperhe,
3366
3367- Mono ja
3368
3369- SnippetCompiler.
3370
3371\
3372
3373Tässä monisteessa tutustumme tarkemmin *Visual Studio 2010 Express*
3374-tuoteperheeseen kuuluvaan *Visual C\# 2010 Express* -kehittimeen. Muita
3375perheeseen kuuluvia ilmaisia C\#-kehittimiä ovat mm. *Visual Studio 2010
3376Express for Windows Phone* sekä *Visual Web Developer 2010 Express*
3377
3378Kaikki ohjeet on testattu toimiviksi Visual C\# 2010 Express sekä Visual
3379Studio 2010 Ultimate -versioilla, luonnollisesti Windows-ympäristössä.
3380
338110.1 Asennus
3382------------
3383
3384Visual Studion (VS) maksullinen - ja Jyväskylän yliopiston
3385opiskelijoille maksuton - Ultimate-versio, on ladattavissa Microsoftin
3386yliopistoyhteistyöpalvelusta, kirjoitushetkellä (elokuu 2012) nimeltään
3387DreamSpark Premium. Edellä mainittu Express-versio on saatavilla
3388ilmaiseksi Microsoftin verkkosivuilta. Express-versio riittää muilta
3389osin tämän kurssin tarpeisiin, mutta siitä puuttuvat testausominaisuudet
3390(ks. luku 11). Muistathan, että VS on saatavissa vain
3391Windows-käyttöjärjestelmille. Linux- ja Mac OS X -ympäristöihin on
3392saatavilla ainakin Mono-sovelluskehitin, mutta tällä kurssilla
3393käytettävä Jypeli-ohjelmointikirjasto vaatii toimiakseen
3394Windows-käyttöjärjestelmän.
3395
339610.2 Käyttö
3397-----------
3398
3399### 10.2.1 Ensimmäinen käyttökerta
3400
3401Kun käynnistät VS:n ensimmäisen kerran, kysyy VS millä oletusasetuksilla
3402haluat valikoita ja toimintoja käyttää. Valitse Visual C\# Development
3403Settings.
3404
3405Aluksi rivinumerot eivät ole käytössä. Koodin seuraamisen
3406helpottamiseksi otetaan ne käyttöön kohdasta Tools → Options → Text
3407Editor → C\# → Line Numbers. Jos Error list-ikkuna ei ole jo näkyvissä
3408ruudun alareunassa, kannattaa se ottaa käyttöön: View → Error List.
3409
3410### 10.2.2 Projektit ja solutionit
3411
3412Visual Studiossa on *solutioneja* ja *projekteja*. Yhdessä solutionissa
3413voi olla monta projektia ja jokaisen projektin täytyy kuulua johonkin
3414solutioniin. Uuden ohjelman kirjoittaminen alkaa aina projektin
3415perustamisella johonkin solutioniin, jolloin myös solution luodaan
3416samalla, ellei sitä ole jo tehty.
3417
3418Hierarkia ei ole kiveen hakattu, mutta solutioneja ja projekteja voi
3419hahmottaa esimerkiksi seuraavasti:
3420
3421- Jokainen demokerta (tai luento, ohjauskerta tms) on uusi solution,
3422 eli kun aloitat tekemään *ensimmäistä* demotehtävää (ohjaustehtävää)
3423 niin toimitaan seuraavasti
3424
3425 - Klikkaa File → New project (Ctrl+Shift+N)
3426
3427 - Valitse projektin tyyppi: Jos teet konsoliohjelmaa niin valitse
3428 Visual C\# -kohdasta Console Application. Jos teet Jypeli-peliä,
3429 valitse Visual C\# → Jypeli-kohdasta haluamasi projektimalli
3430 (esimerkiksi FysiikkaPeli).
3431
3432 - Anna projektille (eli tehtävälle) nimi kohtaan Name, esimerkiksi
3433 Lumiukko tai HelloWorld. Tarkista demotehtävien nimeämiskäytäntö
3434 opettajalta.
3435
3436 - Laita Location-kohtaan demotehtäviesi juuripolku, eli vaikkapa
3437 C:\\MyTemp\\\<omatunnus\>\\ohj1\\demot. Laita omatunnus kohtaan
3438 luonnollisesti yliopiston mikroverkon käyttäjätunnuksesi. Älä
3439 käytä ääkkösiä tai välilyöntejä kansioiden eikä tiedostojen
3440 nimissä, tulemme yleensä toimeen myös ilman niitä, mutta
3441 ongelmia ääkköset ja erikoismerkit aiheuttavat usein.
3442
3443Huomaa! Tarkista luennoitsijalta demotehtävien tallennuspaikka
3444yliopiston mikroverkossa.
3445
3446- - Valitse Solution-valikosta Create new Solution ja paina Create
3447 directory for solution (tärkeä)
3448
3449 - Laita Solution Name kohtaan demoN (N = demokerran numero),
3450 esimerkiksi demo3
3451
3452 - Nyt sinulle on luotu uusi solution ja yksi projekti solutionin
3453 sisään.
3454
3455- Kun haluat *lisätä* demotehtäviä (projekteja) tiettyyn demokertaan
3456 (solutioniin) toimi näin
3457
3458 - Avaa sen demokerran solution (.sln-tiedosto) johon haluat
3459 tehtävän lisätä (ellei se ole jo auki Visual Studiossa).
3460
3461 - File → New project *tai* Solution Explorerissa klikkaa hiiren
3462 oikealla solutionin päälle, ja klikkaa Add → New project
3463
3464 - Anna projektille nimi, jätä Location ennalleen, ja valitse
3465 Solution-valikosta Add to Solution. Solution Name -kohta
3466 himmenee ja Location-kohtaan pitäisi tulla automaattisesti
3467 lisäteksti demoN.
3468
3469Näin tehtynä kaikki yhden demokerran tehtävät löytyvät "saman katon
3470alta" eli yhden solutionin kaikki projektit menevät samaan kansioon.
3471Resurssienhallinnassa hakemistopuusi voisi näyttää esimerkiksi tältä.
3472
3473``` {.esimerkki-western lang="zxx" xml:lang="zxx"}
3474ohj1
3475 |
3476 +--demot
3477 | +--demo1
3478 | | +--HelloWorld
3479 | | +--Lumiukko
3480 | | '-demo1.sln
3481 | '--demo2
3482 | +--Lumiukko2
3483 | '--LukujenLaskemista
3484 '--ohjaukset
3485 +--ohjaus1
3486 | +--HelloWorld
3487 | '--Lumiukko
3488 '--ohjaus2
3489```
3490
3491Yksittäisten projektien kansioihin (tässä HelloWorld, Lumiukko,