Johdanto C#-ohjelmointiin

Yleistä

C# on Microsoftin kehittämä ohjelmointikieli, joka julkaistiin kesäkuussa 2000. Kieli kehitettiin yhdistämään C++:n tehokkuus ja Javan helppokäyttöisyys. Kielen on kehittänyt Anders Hejlsberg, jolla oli paljon aikaisempaa kokemusta mm. Turbo Pascal, Delph ja J++ kehitystyöstä. C#:n kehityksen päätavoitteena oli luoda useampiin ympäristöihin helppokäyttöinen oliopohjainen ohjelmointi. Kielenä C# on vahvasti tyypitetty eli muuttujille on annettava jokin tietotyyppi (esim. kokonaisluku, merkkijono, ...).

C# ohjelmointikielen tarkka ja täydellinen spesifikaatio C# Language Specification on ladattavissa Microsoft Download Center:ssä. Suosittelen tutustumaan mieluummin kuin "alkaa arvailemaan".

Aika moni ohjelmoija pitää C#:a Microsoftin vastauksena Java-ohjelmoinnille. Mielestäni tässä ei ole tärkeää lähteä erottelemaan tai vertailemaan näitä kahta ohjelmointikieltä. Tällä kurssilla on tärkeintä oppia lisää ohjelmointia ja sillä ei ole merkistystä tehdäänkö se C#- vai Java-ohjelmointikielellä. Molemmilla on tärkeä rooli tämän päivän ohjelmistoteollisuudessa.

Tiobe-indeksin mukaan C# on pysynyt jo pitkään viiden suosituimman ohjelmointikielen joukossa: Tiobe

Ensimmäinen esimerkki

Alla on näkyvissä ensimmäinen pieni C#-ohjelmoinnilla toteutettu konsolipohjainen ohjelma (FirstTest.cs), joka tulostaa henkilön nimen näyttölaitteelle.


    

Rivi 1: Sovellus käyttää System nimiavaruutta, sisältää C#:n perusluokkia, joita käytetään yleisesti
Rivi 3: Määrittelee tämän sovelluksen nimiavaruuden
Rivi 5: Määrittelee sovelluksen pääluokan
Rivi 6: Määrittelee sovelluksen main-metodin, ohjelman aloituspiste on aina staattinen main-metodi
Rivit 9-14: Sovelluksen toiminnalliset lauseet

Sovelluksen kääntämäinen ja suorittaminen

Kirjoitettu C#-koodi voidaan kääntää ajettavaksi sovellukseksi käyttämällä csc.exe-komentoa Windowsin komentokehotteessa tai suoraan Visual Studio IDE:ä kääntämään ja suorittamaan sovellus. Molemissa tapauksissa tuotetaan .exe-päätteinen tiedosto, jota voidaan suorittaa Windows-ympäristössä.

C#-ohjelmointikoodia voidaan kirjoittaa milla tahansa tekstieditorilla. Tämän kurssin kaikki harjoitteet ohjelmoidaan ja suoritetaan Visual Studiosta käsin.

C#-ohjelmoinnin perusteet

Nimeäminen

Maailmassa on useita satoja eri ohjelmointikieliä, joilla on jokaisella (tai ainakin usealla) omat tyylinsä kuinka ohjelmointikoodia tulee kirjoittaa. C#:n osalta kannattaa opetella erittäin tarkkaan seuraavat periaatteet: Naming Guidelines

Avainsanat

Ohjelmointikieliin liittyvillä avainsanoilla on tietty erityinen tehtävä ja merkitys. Näitä varattuja sanoja ei voi käyttää omassa ohjelmassa tunnisteina (tietyin keinoin tosin voi, mutta sellaisia kiertoteitä ei kannata käyttää).

C#:n varatut avainsanat löydät täältä: C# Keywords.

Tunnisteet

Tunnisteet ovat ohjelmoijan antamia nimiä muuttujille, luokille, metodeille, jne..., jolla ohjelman eri objektit tunnistetaan. Tunnisteiden nimissä voi käyttää isoja ja pieniä kirjaimia, numeroita sekä esimerkiksi alaviivaa. Tunnisteen ensimmäinen merkki ei voi olla numero.

Hyvä tunnisteen nimi kuvaa hyvin sen sisältöä ja mitaltaan suhteellisen lyhyt, jotta sen kirjoittaminen on nopeaa ja ei virhealtista.

Muuttujat

Muuttujissa säilytetään tietoa ohjelman suorituksen aikana. Sovelluksen muuttujalle pitää antaa nimi (kts. tunniste) sekä sille pitää määritellä tyyppi, jonka mukaista tietoa muuttuja voi sisältää. Muuttujat kannattaa nimetä kuvaavasti, jotta niiden käyttö on selkeää kaikille.

Muuttujien yleinen määrittely on seuraava:


    

Alla on näkyvissä muutamia eri tyyppisiä muuttujien määrittelyjä:


    
    

Tietotyypit

Muuttujien tyyppeinä käytään useasti C#:n sisäänrakennettuja tietotyyppejä. Näiden lisäksi opintojaksolla opetellaan tekemään omia tietotyyppejä (tietueita, lueteltuja tyyppejä, luokkia ja liittymiä).

C#:n tietotyypit löydät täältä: Built-In Data Types.

Oheisessa kuvassa on esitetty C#-tyyppijärjestelmä, eli arvotyypit ja viittaustyypit.

Oheisessa kuvassa on esitelty C#:n käytetyimmät tietotyypit.

Arvotyypit (value type)

Arvotyypit (yllä luetellut tietotyypit) sisältävät muuttujan arvon suoraan ja niiden muistivaraus tehdään pinosta (stack). Parametrien välityksessä arvoparametrien kohdalla käytetään oletuksena aina kopiota. Jos arvotyyppia halutaan käsitellä parametrien välityksessä kuten viittaustyyppejä, tulee sekä kutsussa, että parametrien esittelyssä käyttää ref-avainsanaa.


    

Yllä olevilla numberA ja numberB on omat muistialueensa, rivillä 6 sijoitetaan numberA:n kopio numberB:hen. Demottu myös parametrien välityksessä arvotyypin toimintaa.

Viittaustyypit (reference type)

Viittaustyyppi on nimensäkin mukaisesti viittaus varsinaiseen muuttujaan. Viittaus sijaitsee pinossa, mutta sen varsinainen tieto (string,object - class, liittymät ja delefaatit) varataan sijaitsee keossa (heap). Parametrien välityksessä viittaustyyppien kohdalla toteutetaan myös kopio, mutta alkuperäinen ja parametrinä oleva osoittaa samaan muistialueeseen eli funktiossa/aliohjelmassa/metodissa mahdollisesti muutettu arvo muuttaa myös alkuperäistä.


    

Yllä olevassa rivillä 3 sbA:han sijoitetaan sbB:n viittaus eli molemmat viittaavat samaan muistialueeseen keossa (heap). Demottu myös parametrien välityksessä viitetyyppien toimintaa.

Arvotyypit ja viittaustyypit käyttävät muistia eri tavalla. Arvotyypit tallennetaan pinoon (stack), kun taas viittaustyypin varsinainen tieto on keossa (heap), ja tietoon on viittaus pinosta. Tämä luo mielenkiintoisia seurauksia ja mahdollisuuksia olio-ohjelmointiin. Alla oleva kuva selventää hieman muistin erilaista käyttöä.

Enum

Enum on lueteltu tyyppi, jonka jokaista jäsentä vastaa numeroarvo. Enumia käytetään yleensä tilanteessa, jossa tarvitaan kuvata jotain tilaa tai vaihtoehtoa. Ihmisen on helpompi muistaa käsitteitä kuin numeroita.

Voitaisiin tutkia esim. äänenvoimakkuuden arvoa seuraavasti. Tällöin tulisi muistaa, että esim. numero 1 tarkoittaa medium äänenvoimakkuutta.


    

Sama asia voitaisiin toteuttaa lueteltujen tyyppien avulla seuraavasti, jolloin mitään erityisiä numeroarvoja ei tarvitsisi muistaa.


    

Enum-numeroarvo on teknisesti kokonaisluku (alkaa nollasta), muuta siihen voidaan esittelyn yhteydessä alustaa mikä tahansa haluttu arvo.

Taulukot

Taulukko on ohjelmoijan perustietorakenne silloin, kun on ohjelmoinnissa on tarve käyttää useampaa samantyyppistä muuttujaa. Taulukon muuttujiin (alkioihin) voidaan viitata taulukon nimellä. Taulukon indeksointi alkaa nollasta eli taulukon ensimmäinen alkio on positiossa nolla.


    
    

Kommentit

Kommentointi kuuluu ohjelmointiin erittäin tärkeänä osana. Kommentoinnin tarkoitus on parantaa koodin luettavuutta ja antaa lisätietoa koodin toiminnasta. Kommentointi helpottaa sovelluksen ylläpitoa ja jatkokehitystä. Valitettavan usein ohjelmoijat jättävät kommentoinnin tekemättä tai ainakin tekevät sen puutteellisesti.

Kommentoimaton ohjelma ei ole merkki ohjelmoijan asiantuntevuudesta, vaan laiskuudesta!

Kommentointi voidaan toteuttaa muutamalla eri tavalla:


    

Ohjelmoinnin kasvaessa ja varsinkin silloin kun aletaan tehdä omia luokkia, käyttöön tulee myös dokumenttikomentti. Tiettyä syntaksia noudattamalla voidaan dokumenttikommentit muuttaa sellaiseen muotoon, että niitä voidaan tarkastella esimerkiksi nettiselaimella. Dokumenttikommentti on syytä kirjoittaa ainakin ennen jokaista luokkaa, pääohjelmaa ja toimintoa ennen. Lisäksi jokainen C#-tiedosto alkaa dokumenttikommentilla, josta selviää tiedoston tarkoitus, tekijä, versio (ja esim. päivämäärä).

Dokumenttikomentti kirjoitetaan siten, että rivin alussa on aina aina kolme vinoviivaa. Dokumentointi toteutetaan tagien avulla (kuten HTML-kielessä). Suositeltavat tagit löytyvät täältä: Recommended Tags for Documentation Comments (C# Programming Guide).


    
    

Operaattorit

Ohjelmointiin liittyvien operaattorien tehtävä on sijoittaa ja/tai vertailla kahden eri operandin arvoja toisiinsa.

Alla muutamia operattoreita, jotka esiintyvät ohjelmoinnissa useasti:

operaattori tehtävä esimerkki
= sijoitus int luku = 10;
== yhtäsuuret if (luku == 10) { }
!= erisuuret if (luku != 10) { }
< pienempi if (luku < 10) { }
<= pienempi tai yhtäsuuri if (luku <= 10) { }
> suurempi if (luku > 10) { }
>= suurempi tai yhtäsuuri if (luku <= 10) { }
+ yhteenlasku int luku = 10 + 5;
+ merkkijonojen liittäminen string kokonimi = "Kirsi" + "Kernel";
- vähennyslasku int luku = 10 - 5;
* kertolasku int luku = 10 * 5;
/ jakolasku int luku = 10 / 5;
% jakojäännös int luku = 10 % 5;
++ lisää lukua yhdellä luku++;
-- vähennä lukua yhdellä luku--;
+= lisää itseensä luku += 10;
-= vähennä itseensä luku -= 10;
/= jaa itseensä luku /= 10;
*= kerro itseensä luku *= 10;
%= jakojäännös itseensä luku %= 10;
&& Ja if (ikä >= 18 && ikä <= 60) { }
|| Tai if (vuosi == 2015 || vuosi == 2016) { }
! Negaatio bool aikuinen = true; if (!aikuinen) { }

Oheisessa kuvassa on esitetty yhteenveto C#:n operaattoreista.

Kontrollirakenteet

if-ehtolause

Valintarakenteista if-lausetta käytetään testaamaan onko sulkeissa annettu lauseke kokonaisuudessaan tosi tai epätosi. Ainoastaan siinä tapauksessa, että ehtolause on tosi, suoritetaan ehtolauseen jälkeinen lauseke tai lauselohko. Suoritettavat lauseet on suljettava aaltosulkujen sisälle (poikkeus yhden lauseen tapaus, jolloin aaltosulkeita ei tarvita). if-lauseeseen on mahdollisuus liittää else-lohko, joka suoritetaan, jos varsinainen if-lauseen ehto ei toteudu. Ehtolauseita voidaan myös ketjuttaa. Tällöin toteutuneen ehdon jälkeen ei enään tarkisteta jäljelle jääneitä ehtoja. Tällöin puhutaan if else if -lauseryhmästä.


    

Alla muutamia esimerkkejä:


    
    

switch-valintalause

Ketjutetun if else if -lauseen kasvaessa pitkäksi ohjelmasta muodostuu helposti hankalasti luettava. Tällöin on parempi käyttää switch-lausetta. Switch-lauseessa on myös hieno mahdollisuus yhdenvertaistaa valintoja jättämällä halutuista case-vaihtoehdoista break-lause pois, jolloin suoritetaan myös seuraava case-kohta.


    
    

while-toistolause

While-silmukka on yksinkertainen toistorakenne. Siinä testataan onko ehtolause tosi ja silmukan sisällä olevien lauseiden toistaminen jatkuu niin kauan aikaa, kun ehto pysyy totena. Heti kun ehto ei enään ole voimassa, sovelluksen suoritus jatkuu toistolausetta seuraavasta lauseesta.


    

Alla oleva esimerkki tulostaa luvut 1-10:


    
    

do-while-toistolause

Rakenne muistuttaa while-toistolausetta. Merkittävin ero on kuitenkin siinä, että do while -lauseessa ehto suoritetaan vasta lauseiden suorittamisen jälkeen eikä ennen lauserakennetta. Näin ollen do while -toistolauserakenne suoritetaan ainakin yhden kerran.


    

Alla oleva esimerkki tulostaa satunnaisia lukuja väliltä 0-10, kunnes satunnainen luku on 10.



    

Pikku refaktorointi tehtävä

Alla olevassa esimerkissä käyttäjältä kysytään yksi luku väliltä 1-21. Luku tarkistetaan, että se on annetulla välillä. Jollei se ole, niin käyttäjälle annetaan ilmoitusasiasta, ja ohjelman suoritus päättyy. Tee ohjelmaan seuraavat muutokset: 1) Muuta ohjelmaa siten, että käyttäjältä kysytään lukua niin kauan, että se on annetulta väliltä 2) Tee ohjelmaan muutos siten, että käyttäjä voi pelata niin kauan kunnes hän antaa syötteeksi: X tai exit. Jos käyttäjä antaa jonkin muun merkkijonon, joka ei ole kokonaisluku, käyttäjälle näytetään ohje sallituista syötteistä. 3) Tee muutos, että myös pöydän korttien arvo arvotaan väliltä 10-21. Näytä arvottu luku tuloksen yhteydessä.


    
    

for-toistolause

for-silmukka toistaa lausetta tai lauseita, kunnes toistoehto ei ole enään voimassa. Toistorakenetta käytetään yleensä yksikertaisissa toistolauseissa, joissa toistomäärä on tiedossa. Lauserakenne eroaa huomattavasti muista toistorakenteista. for-silmukassa on tavallisesti mukana kaikki kolme osaa:
- alustus: määritellään kierroslaskuri, jonka avulla määritellään for-silmukan toistomäärä
- ehto: määrää toiston jatkumisen
- päivitys: kasvatetaan tai vähennetään kierroslaskuria


    

Alla oleva esimerkki tulostaa kymmenen tähtimerkkiä:


    
    

foreach-toistolause

foreach-toistolauseella voidaan käydä taulukon tai kokoelman alkiot helposti läpi. Toiston aikana kokoelmasta ei saa poistaa tai lisätä alkioita.


    

Alla oleva tulostaa nimet konsolille:


    
    

break-hyppylause

break-lauseella voidaan katkaista toistolauseen toisto. Toinen yleinen käyttökohde break-lauseelle on aikaisemmin esitelty switch-lauseesta poistuminen.

Alla olevassa esimerkissä poistutaan silmukasta, kun käyttäjä antaa negatiivisen luvun:


    
    

continue-hyppylause

continue-lauseella voidaan aloittaa toistorakenteen "uusi kierros". Lauseella voi siis ohittaa loput toistolauserungon lauseista.


    
    

return-hyppylause

return-lause lopettaa metodin suorittamisen ja palauttaa arvon, jos palautin tyyppi on määritelty metodin esittelyssä.



	

Kulttuurin huomioiminen .NET Frameworkissa

Tiettyissä tilanteissa on tärkeää esittää luvut, päivämäärät jne oikeassa muodossa loppukäyttäjälle. Seuraava esimerkki valaisee asiaa kuinka homma voidaan hoitaa .NET:ssä.