9789151108445

Page 1

Programmering 1 Magnus Lilja Ulrik Nilsson Dennis Berling

C#

Andra upplagan

51108445.1.1_omslag.indd 1

2022-03-23 13:05


Innehåll

Förord

5. Operatorer

3

1. Introduktion

6

1.1 Grunder 7 1.2 Datorns funktion 9 1.3 Programstruktur 11 1.4 Om den här boken 12 Repetitionsfrågor 13 Uppgifter 13

2. Introduktion till utvecklings­miljön Visual Studio 2019 14 2.1 Visual Studio 15 2.2 Ett första exempel 18 2.3 Ett C#-programs struktur 21 2.4 Olika typer av fel 24 Sammanfattning 25 Repetitionsfrågor 26 Uppgifter 27

3. Variabler

28

3.1 Grunder 29 3.2 Deklaration 31 3.3 Tilldelning 31 3.4 Typomvandlingar 32 3.5 Tal 34 3.6 Text 36 3.7 Tecken 38 3.8 Unicode 39 3.9 Objekt 42 Sammanfattning 44 Repetitionsfrågor 46 Uppgifter 47

4

4. Felsökning

48

Sammanfattning 53

51108445.1.1_inlaga.indd 4

54

5.1 Grunder 55 5.2 Aritmetiska operatorer 55 5.3 Tilldelande aritmetiska operatorer 58 5.4 Förändringsoperatorer 58 5.5 Relationsoperatorer 60 5.6 Logiska operatorer 62 5.7 Prioriteringsregler 65 Sammanfattning 67 Repetitionsfrågor 68 Uppgifter 69

6. Aktivitetsdiagram och pseudokod 70 6.1 Algoritmer och pseudokod 71 6.2 Kontrollstrukturer 72 6.3 Aktivitetsdiagram 72 Sammanfattning 76 Repetitionsfrågor 76 Uppgifter 77

7. Villkorssatser

78

7.1 if-else 79 7.2 if 84 7.3 if – else if 87 7.4 switch-case 90 7.5 Att jämföra strängar 93 7.6* Villkorsoperatorn ? : 95 Sammanfattning 98 Repetitionsfrågor 100 Uppgifter 102

8. Grafiska gränssnitt och grafik

104

8.1 Grafiska gränssnitt 105 8.2 Grafik 112 Sammanfattning 116 Repetitionsfrågor 118 Uppgifter 119

2022-03-23 13:32


13. Samlingar

122

9.1 While 123 9.2 Do-while 126 9.3 For 127 9.4 Nästlade loopar 129 9.5 Continue och break 131 9.6 Fält 132 Sammanfattning 138 Repetitionsfrågor 139 Uppgifter 141

10. Metoder

Innehåll

9. Repetition

200

13.1 List 201 13.2 Stack 206 13.3 Kö 210 Sammanfattning 214 Repetitionsfrågor 215 Uppgifter 216

14. Rekursiva metoder

142

10.1 Att skriva och anropa en metod 143 10.2 Metoder med flera parametrar 146 10.3 Värdeparametrar 148 10.4 Metoder utan returvärde 150 10.5 Referens och out-parametrar 152 10.6 Fält som parameter 156 Sammanfattning 158 Repetitionsfrågor 160 Uppgifter 162

11. Objekt och objektorientering.

218

14.1 Summor och produkter 219 14.2 Talföljder 222 14.3 Fält 225 14.4 Ett grafiskt exempel 228 Sammanfattning 232 Repetitionsfrågor 233 Uppgifter 234

15.  Facit till teorifrågor och övningar 236 Register

279

164

11.1 Vad är objekt och objektorientering? 165 11.2 Objekt på praktisk nivå 169 11.3 Klasser med C# och Visual Studio 172 11.4 Förbättringar av programmet 179 Sammanfattning 185 Repetitionsfrågor 187 Uppgifter 188

12. Sortering och sökning 12.1 Sortering 191 12.2 Bubbelsortering 193 12.3 Sökning 195 Sammanfattning 198 Repetitionsfrågor 199 Uppgifter 199

51108445.1.1_inlaga.indd 5

190

5

2022-03-23 13:32


1

Introduktion

6

Something mysterious is formed, born in the silent void. Waiting alone and unmoving, it is at once still and yet in constant motion. It is the source of all programs. I do not know its name, so I will call it the Tao of Programming. If the Tao is great, then the operating system is great. If the operating system is great, then the compiler is great. If the compiler is great, then the application is great. The user is pleased and there exists harmony in the world.

The Tao of Programming flows far away and returns on the wind of morning. The Tao of Programming

51108445.1.1_inlaga.indd 6

2022-03-23 13:32


En dator är en på många sätt fantastisk maskin. Den är olik de flesta andra maskiner som människan använt genom historien. Dessa maskiner har varit konstruerade för att utföra en speciell arbetsuppgift. En del av dem har varit ganska komplicerade och sinnrika, men de har fortfarande bara kunnat användas till en enda sak. Vindmöllorna kunde mala mjöl. Ångmaskinen gav mekanisk kraft och radioapparaterna kunde omvandla radiovågor till ljud.

1. Introduktion

1.1 Grunder

Hårdvara En dator däremot är sällan konstruerad för ett speciellt ändamål. Datorer används för att styra andra maskiner, kommunicera, övervaka, underhålla, för att lagra stora mängder information och för många andra ändamål. Men alla dessa datorer, fastän de kommer i olika storlekar och skepnader, är principiellt lika under skalet. De innehåller en eller flera processorer, chip och andra elektroniska komponenter, sådant som vi brukar kalla hårdvara. Men det finns inte många processorer som bara kan visa film, eller bara kan öppna och stänga en dörr. Om man till exempel vill övervaka och styra in- och utpassering genom dörrarna i en byggnad kan man i stora drag köpa vilken dator som helst. Samma dator kan förmodligen dessutom användas till att visa film, skicka e-post och mycket annat.

Mjukvara För att få en dator att utföra en speciell uppgift krävs ett speciellt program. Program kallas även för mjukvara. Ett program är en mängd instruktioner som talar om vad datorn ska göra. Om en knappsats vid en dörr skickar en sifferkombination till en dator kan processorn till exempel svara med en signal till motorlåset i dörren. Men samma siffror från en film innehåller förmodligen färgen på en pixel. För att en pixel på skärmen ska tändas med denna färg behövs istället ett helt annat program, ett program som skickar en signal till grafikkortet istället för till dörren.

Maskinkod Det finns bara ett begränsat antal operationer till varje processortyp. Operationerna är väldigt enkla, till exempel ”Flytta tal A till adress 10” där adress 10 kan vara en plats i datorns minne, en pixel på skärmen eller ett motorlås i en dörr, eller någon annan elektronisk krets som är ansluten till datorn. Andra operationer är till exempel ”addera tal A och B” eller ”jämför tal A med B”. Dessa grundläggande operationer kal�las för datorns maskinkod, fast i realiteten består de av siffror. Addera kan ha maskinkoden 03. Genom att kombinera instruktionerna på olika sätt kan man få datorn att utföra en viss uppgift. Att få ett program att visa en enkel figur på skärmen kräver till exempel en hel mängd operationer.

7

Högnivåspråk Ett modernt program innehåller hundratusentals eller miljontals maskinspråks­ instruktioner. Att skriva ett större program på maskinspråk skulle vara näst intill omöjligt. Därför har man uppfunnit programmeringsspråk vars kommandon liknar vanligt människospråk. De kallas högnivåspråk för att skilja dem från maskinspråk. Man kan till exempel skriva saker som ”A+B” för att addera två tal, eller ”DrawRectangle” för att visa en rektangel på skärmen. Det finns och har funnits ganska många olika högnivåspråk. Ett av de stora är för tillfället C# (uttalas c-sharp på engelska). C# är en vidareutveckling av Java och C++, som i sin tur är en vidareutveckling av C. Andra kända språk är Visual Basic och Python.

51108445.1.1_inlaga.indd 7

2022-03-23 13:32


1. Introduktion

Kompilering Högnivåspråk skrivs i vanliga textfiler och kallas för källkod. Källkoden måste översättas till maskinspråk innan de kan användas av en processor. Översättningen kan ske i flera steg och kallas kompilering. Kompilering genererar vanligen filer med filändelsen .exe om programmet ska köras på Windows-datorer, eller .app om programmet ska köras på Macintosh-datorer. Om man vill att programmet ska kunna köras på både Windows och Mac (eller andra operativsystem) är det vanligt att låta varje dator som ska köra programmet själv göra det sista översättningssteget. Det kallas för interpretering eller ”just-in-time” kompilering (JIT). Bilden nedan visar hur översättningen fungerar i Visual C# för ett spel som heter Pacman, bara för att ta ett exempel. CIL betyder Common Intermediate Language och är ett mellansteg mellan källkod och maskinkod. Programmerarens dator

Spelarens dator

Källkod

CIL

CIL

pacman.cs

pacman.exe

pacman.exe

kompilering

bbUU

Maskinkod

J IT

Programmet distribueras oftast via internet

Microsoft Visual C# och .NET Microsoft Visual C# är ett program för att skapa andra program. Communityversionen är gratis och finns att ladda ner från internet. Microsoft Visual C# är en del av en plattform som kallas .NET. Plattformen består av ett antal filer och innehåller bland annat färdigskrivna programbitar. Många uppgifter som ett program ska kunna genomföra är rutinmässiga, som till exempel att spara data till en fil på hårddisken. För att slippa skriva samma kod varje gång man vill lägga till en spara-funktion använder man istället spara-funktionen i .NET. Det betyder att alla program du skriver i C# är beroende av .NET-plattformen. De går inte att köra på datorer som saknar .NET.

8

Thus spake the ­master programmer: – Without the wind, the grass does not move. Without software, ­hardware is useless. The Tao of Programming

51108445.1.1_inlaga.indd 8

2022-03-23 13:32


Man behöver inte vara någon datortekniker för att kunna programmera, men man måste känna till de tre komponenterna processorn, arbetsminnet och hårddisken.

Fil Skiva

På hårddisken finns data lagrat i magnetiska spår eller halvledarkomponenter. Datan är uppdelad i filer. Hårddisken är till för att spara data när datorn är avstängd, fast den kan också användas som reserv till arbetsminnet.

Skrivhuvud

1. Introduktion

1.2 Datorns funktion

När en fil öppnas laddas den till arbetsminnet. I arbetsminnet lagras också all data som strömmar in i datorn från dess olika portar, där till exempel tangentbordet och musen är anslutna. Arbetsminnet kallas även RAM-minne, primärminne eller internminne. Det är direktkopplat till processorn. Processorn läser data från arbetsminnet, genomför operationer och skickar tillbaka svaret till arbetsminnet. Processorn kan liknas vid datorns hjärna. Men den tänker inte, den följer bara programmets instruktioner. Låt oss studera hur processorn och arbetsminnet arbetar tillsammans med ett exempel. Antag att du öppnar programmet Kalkylatorn (filen calc.exe) för att räkna ut vad 4 + 3 blir. Programfönster

Arbetsminne A

B 4

C +

D 3

7

9 Användaren

Processorn

1

Startar programmet

Ritar fönstret, reserverar plats i minnet och väntar sedan på input.

2

Klickar på knappen 4

Lagrar värdet 4 i arbetsminnet (på reserverad plats A).

3

Klickar på knappen +

Lagrar värdet ’+’ i arbetsminnet (på reserverad plats B).

4

Klickar på knappen 3

Lagrar värdet 3 i arbetsminnet (på reserverad plats C).

5

Klickar på knappen =

Undersöker värdet i B. Väljer operationen ADD och läser in värdena i A och C. Skickar tillbaka värdet 7 till arbetsminnet (D). Ritar om fönstret med värdet i D i textrutan. Hoppar tillbaka i instruktionskön till den plats där den väntar på input.

51108445.1.1_inlaga.indd 9

2022-03-23 13:32


1. Introduktion

Lägg märke till följande: l Programmet calc.exe innehåller instruktionerna till vad processorn ska göra. l Programmet är händelsestyrt. Om användaren inte gör något händer inget. l Programmet är sekventiellt. Alla instruktioner genomförs en i taget i en given ordning. l Programmet är repeterbart. Processorn kan hoppa till olika instruktioner, även bakåt, och på så sätt göra om samma sak många gånger. l Minnet delas in i mindre platser som kallas för variabler, där varje plats ges ett unikt namn och har utrymme för ett värde. Som programmerare bryr man sig sällan om vad som händer i processorn, men det är bra att ha lite koll på vad som händer i arbetsminnet när man reserverar plats och skickar runt värden mellan platserna. Hur detta går till beskrivs i kapitlet om variabler, men du kommer förmodligen att förstå programmering mycket bättre om du redan nu lär dig att tänka på en variabel som en minnesplats som innehåller ett värde.

10

51108445.1.1_inlaga.indd 10

2022-03-23 13:32


En text är uppbyggd av meningar som delas in i avsnitt med olika rubriker, som i den vänstra spalten nedan. På samma sätt är programkod uppbyggd av satser och programblock, som i den högra spalten. Koden här är inte riktig kod, utan en sorts halvkod som bara visar strukturen. Precis som man avslutar en mening med punkt måste man avsluta en sats med semikolon (;). Vanlig text

Programkod

Rubrik 1

Programblock 1 { Sats 1; Sats 2; Sats 3; }

Mening 1. Mening 2. Mening 3. Rubrik 2 Mening 4. Mening 5.

1. Introduktion

1.3 Programstruktur

Programblock 2 { Sats 4; Sats 5; }

Lägg märke till att programblocket består av en rubrik som kallas för programblockets huvud, följt av en klammerparentes { } som innehåller programblockets satser. Mellan satserna kan man ha hur många mellanslag, tabbar eller tomma rader man vill. Mellanslag, tabbar och tomma rader gör det lättare att läsa koden, men de kompileras inte till maskinkoden. Kompilatorn bestämmer vad som tillhör programblocket bara med hjälp av klammerparenteserna.

Eftersom kod är svårare att läsa än vanlig text brukar man göra blockstrukturen lättare att se genom att bara skriva en sats per rad, och dessutom indentera satserna med en tab eller några mellanslag. Då ser det ut så här:

Programblock 1 { Sats 1; Sats 2; Sats 3; } Programblock 2 { Sats 4; Sats 5; }

Fördelen med indentering blir särskilt tydlig när man har programblock inuti varandra:

11

Programblock 3 { Sats 1; Sats 2; Programblock 3A { Sats 3; Sats 4; } }

51108445.1.1_inlaga.indd 11

2022-03-23 13:32


1. Introduktion

Alla satser i ett programblock utförs i den ordning de står, men programblocken behöver inte köras i ordning. Ett programblock kanske körs när användaren klickar på en knapp i programmets fönster. Ett annat programblock körs när användaren klickar på en annan knapp. Då är det användaren som bestämmer vilken ordning blocken körs i. Därför är det väldigt viktigt att använda indentering så att man lätt ser vilka satser som utförs tillsammans. Det finns olika sorters programblock. Vissa kan man skriva i en egen fil, medan andra vanligen står inuti ett yttre programblock. Nedanstående översikt ger en tjuvtitt på några olika sorters programblock som du kommer att stöta på i boken.

Metod En metod innehåller oftast bara variabler och satser.

Klass (class) En klass innehåller oftast bara variabler och metoder, men kan även innehålla andra klasser, som då kallas nästlade klasser. Vanligen skriver man klasser i separata filer.

Namnrymd (namespace) En namnrymd innehåller framför allt klasser, men kan även innehålla andra namnrymder. Som programmerare väljer man namn på sina egna klasser, och varje namn måste vara unikt. Det får inte finnas två klasser med samma namn i ett program. I större program med många klasser kan det bli svårt att välja bra och beskrivande namn till alla. Då används namnrymder.

1.4 Om den här boken I bokens text står det ibland om användaren. Med användaren menas den person som ska köra programmet, till skillnad från programmeraren som skapar programmet. Det är du som är programmerare, men du blir förstås användare när du testar dina program.

12

51108445.1.1_inlaga.indd 12

Boken är upplagd så att teori varvas med exempel, övningar och frågor. Övningar är sådana som du ska programmera i Visual Studio. Frågorna behöver du bara fundera över och svara på i boken eller ett anteckningsblock. I slutet av varje kapitel finns en sammanfatting, repetitionsfrågor och uppgifter. Du gör dem på samma sätt som övningarna inne i kapitlet.

2022-03-23 13:32


rf 1.1 Vad menas med kompilering? rf 1.2 Vad innebär det att ett program är händelsestyrt?

1. Introduktion

Repetitionsfrågor

rf 1.3 Vad är en variabel? rf 1.4 Vad har mellanslag, tabbar och rader för betydelse i programkod?

Uppgifter 1.1 Nedan finns halvkod som innehåller kodblock och satser. Strukturera upp koden med rader och indentering så att man lätt ser var ett block börjar och slutar, och vilka block satserna tillhör. a) Programblock 1{Sats 1; Programblock 2{Sats 2; Sats 3;}} b) Programblock 1{Sats 1; Sats 2; Programblock 2{Sats 3; Sats 4; Programblock 3{Sats 5;} Sats 6;}}

13

51108445.1.1_inlaga.indd 13

2022-03-23 13:32


11

Objekt och objektorientering

164

Objekt och objektorientering är ett sätt att organisera programkod så att programvara blir lättare att bygga men också enklare att överskåda och underhålla mellan olika versioner. Det är en generell programmeringsidé som inte bara är knuten till C# utan används idag i många olika programmeringsspråk.

51108445.1.1_inlaga.indd 164

2022-03-23 13:32


När man börjar med programmering upptäcker man snabbt att nästan alla programmeringsspråk hävdar att de ”stödjer objekt”, ”är objektbaserade”, eller finast av allt, ”är fullständigt objektorienterade”. Det här med objekt verkar vara en viktigt egenskap hos ett programmeringsspråk, så vad är objekt och objektorientering? Svaret på den frågan är enklast att besvara på två nivåer. Först en konceptuell som förklarar nyttan med objekt på ett idemässigt övergripande sätt men sedan också en praktisk som visar hur objektorientering går till när faktisk programkod ska skrivas. På konceptuell nivå representerar objekt saker, föremål eller entiteter som är viktiga i ditt program, nästan alltid substantiv t.ex. kund, avtal, faktura o.s.v. På praktisk nivå fungerar objekt som specialutvecklade datatyper speciellt anpassade för de arbetsuppgifter som programmet är gjort för att lösa.

11. Objekt och objektorientering.

11.1 Vad är objekt och objektorientering?

De båda definitionerna samverkar men förklarar inte fullt ut varför objekt finns och gärna används i många programmeringsspråk. Syftet med objekt och objektorientering är helt enkelt att göra det lättare att bygga program och utveckla programvara genom att bättre anpassa de strukturer som används inom programmering till vårt sätt att tänka och uppfatta verkligheten. Vad menas med det? Vi kan ta ett mycket enkelt exempel. T.ex. en person som går ut i en trädgård ser en stor gräsmatta med många träd fulla med röda äpplen. På vägen utanför kör många bilar. En av bilarna är svart, tutar, accelererar och kör iväg väldigt fort. Vad är speciellt här? Jo, för det första är exemplet fullt av saker, d.v.s. fullt av substantiv. Det finns en trädgårdsgång, en gräsmatta, många äppelträd, en väg och många bilar. Sen är vissa saker uppbyggda av andra föremål. T.ex. gräsmattan har många äppelträd där varje träd i sin tur har många äpplen. Vägen har många bilar. En tredje observation är att en del föremål har klart urskiljbara egenskaper. Äpplena är röda och en av bilarna är svart och har hög fart. Till sist kan vi också se att vissa av sakerna kan utföra handlingar. Den svarta bilen tutade och accelererade. Alla dessa punkter tas hänsyn till vid objektorienterad utveckling. l Objekt är saker och föremål. l Ett objekt kan ha egenskaper som t.ex. vara svart eller ha hög fart. l Ett objekt kan utföra handlingar som t.ex. ändra sina egenskaper eller skicka signaler till omgivningen genom förmågor och kommunikation. (den svarta bilen accelererade och tutade) l Ett objekt kan bestå av andra objekt eller ha koppling till andra objekt. (Gräsmattan har många äppelträd där varje träd i sin tur har många äpplen)

165

Ytterligare en sak som objektorientering stödjer är att vi människor gärna använder generaliseringar, d.v.s. medvetet eller inte så gillar vi att ordna saker i hierarkier. Vad menas med det? Jo, antag t.ex. att vi vill sortera upp det vi vet om olika sorters transportmedel. Då kan vi först tänka oss en kategori som heter ”fordon” som i sin tur har flera underkategorier som t.ex. ”hjulfordon”, ”flygplan” och ”båtar”. Kategorin ”hjulfordon” kan sedan i sin tur delas upp vidare som ”personbilar”, ”lastbilar” och ”bussar” o.s.v. Varje undernivå i hierarkin blir allt mer specialiserad. Detta kan göras i så många nivåer av underkategorier som vi tycker behövs. Detsamma gäller så klart för huvudkategorierna ”flygplan” och ”båtar”. Objektorientering hanterar generaliseringar effektivt genom en mekanism som kallas arv. Detta är intressant och tas upp mycket detaljerat i kursen ”Programmering 2” på gymnasiet. Detta betyder dock att vi inte kommer att kunna behandla arv och generaliseringar vidare här i kursen ”Programmering 1”.

51108445.1.1_inlaga.indd 165

2022-03-23 13:32


11. Objekt och objektorientering.

Objektorienteringens ursprung Med objekt och objektorientering följer en strävan att ligga i linje med hur människan resonerar och uppfattar sin verklighet. Objekt är föremål och saker. Varför det blivit så går att förstå om man ser på programmeringsspråkens utveckling vid tidpunkten då objekt och objektorientering började uppfinnas i början av 70-talet. På den tiden skrevs de flesta program med programinstruktioner radvis som långa listor. Stora program kunde vara otroligt komplicerade, tusentals rader långa, där exekveringen kunde hoppa hit och dit genom goto-satser och nästlade if-satser. Det var förenat med stora risker att ändra befintlig äldre kod eftersom det var svårt att förutsäga vilka effekter förändringarna hade. Bara programmerare med lång erfarenhet av just det programmet hade tillräckliga kunskaper att försöka sig på en sådan operation. Med objektorientering ändrades allt det där. På ett orderobjekt kunde utvecklare nu enkelt se vilket produktobjekt som hade beställts av ett visst kundobjekt och vart produkten skulle levereras genom att undersöka kundobjektets adressobjekt. På orderobjektet kunde det finnas förmågor för att hantera betalning och leverans medan förmågor hos kundobjektet t.ex. skötte om order och betalningshistorik för just den kunden. Hur objekten var kopplade till varandra modellerade alltså den data som användes av programmet. Dessa effekter förstärktes genom att på varje enskilt objekt fanns bara de egenskaper som stödde datamodellen. Egenskaper hos objekt förädlades i klasser till medlemsvariabler sin tur utnyttjade programspråkets egna datatyper vilket betydde att objekt blev till specialtillverkade datatyper gjorda för att lösa just denna programvaras speciella problem och uppgifter. Med objekt och objektorientering blev det enklare att bygga ny men också att förvalta befintlig programvara.

Rita för att visa hur du tänker

166

Objekt och objektorientering är alltså en generell idé som inte är knuten till ett visst programmeringsspråk, ämnesområde eller bransch utan kan användas till vilka til�lämpningar som helst. Detta kan demonstreras genom att göra ett objekt som är välkänt för oss. Varför inte ett objekt som representerar en kurs på en svensk gymnasieskola. Ett sådant objekt skulle sen t.ex. kunna användas vidare i ett program för att planera scheman på en skola. Skolverket har långa listor över vilka kurser som finns tillgängliga att läsa på gymnasiet. Två exempel skulle kunna vara Kemi 1 eller Matematik 4 och förutom kursnamn så ger Skolverket också varje kurs en speciell kod som dessa fall är KEMKEM01 och MATMAT04. Alla kurser har en viss längd som anges som poäng och på en viss skola, för en viss klass så kommer det att finnas ett startdatum och ett slutdatum för en viss kurs. I detta läge uppstår ett kommunikationsproblem. När objektorienterat arbete utförs uppstår ofta behov att visa för andra hur objekt ser ut och hur det är tänkt att de ska fungera tillsammans. Här är ett sådant tillfälle. Med ledning av det som nämnts i stycket ovan om kurser på skolverket – hur ska ett kursobjekt se ut? En enkel ritning löser problemen. Bilden här bredvid visar objektet Course som alltså representerar en kurs på en svensk gymnasieskola. I denna typ av ritningar används engelska istället för svenska. Detta görs proaktivt för att undvika eventuella problem med å, ä och ö i den utvecklingsmiljö som senare kommer att användas då programkod ska skrivas. (I princip kan vilket språk som helst användas men engelska har sina fördelar.) Objektets namn hittas längst upp i ritningen, avgränsat med en linje. Sedan följer alla egenskaper som objektet Course har, följt av en avgränsande linje och, längst

51108445.1.1_inlaga.indd 166

Course

Name Code Points Start End IsActive

2022-03-23 13:32


Ett objekt som kan hantera kurser hos den svenska gymnasieskolan har nu på ett snabbt och enkelt sätt modellerats. Med det nya objektet är det möjligt att småningom göra kopior av gymnasiekurser med ett programmeringsspråk. En kopia skulle kunna få namnet ”Kemi 1” med koden ”KEMKEM01” och 100 poäng, detsamma för en annan kopia med namnet ”Matematik 4” med koden ”MATMAT04” o.s.v. för hur många olika sorters kurser som vi vill.

Använd bara egenskaper och förmågor som är viktiga

11. Objekt och objektorientering.

ned, objektets enda förmåga. Alla egenskaper som nämnts tidigare finns med. Kursens namn som Name, kursens skolverkskod som Code, kursens längd som Points och när kursen startar som Start och slutar som End. Längst ner hittas en förmåga med namnet IsActive som kan kontrollera om kursen pågår vid en viss angiven tidpunkt.

En viktig sak med objektorientering är att bara de egenskaper och förmågor som modellerar det som är intressant definieras i objektet. Bara vissa delar av all den omfattande information som skolverket anger om varje kurs valdes ut. Endast de egenskaper som troligen kommer att vara viktiga i framtida programvara tas med i objektet. Ett annat exempel ses till höger. Här representerar ett objekt en fotbollsspelare, ­kanske i ett dataspel eftersom spelarens position anges med egenskaperna X­ Location och YLocation. I alla fall finns förmågor för att springa, hoppa och skjuta med bollen. Ett sista exempel ses nedan till höger. Här är ett objekt som representerar en cirkel, alltså en geo­metrisk figur. Den som skapade objektet anser tydligen att viktiga egenskaper för en cirkel är Radius, ­Position och Color medan viktiga förmågor är GetDiameter och GetArea. I verkligheten kan naturligtvis en fotbollsspelare eller en cirkel ha ett stort antal egenskaper men hos objekten som visas här används bara de som kommer att behövas i den programvara som ska byggas. Detta är viktigt att komma ihåg, använd bara de egenskaper och förmågor som kommer att vara till nytta i det program som så småningom ska skrivas.

SoccerPlayer

Name Number XLocation YLocation Run Jump KickBall Circle

Radius Position Color GetDiameter GetArea

51108445.1.1_inlaga.indd 167

167

2022-03-23 13:32


11. Objekt och objektorientering.

Objekt i andra objekt Nu har enskilda objekt behandlats men verkligheten är mer komplicerad än så. Objekt kan ibland bestå av eller ha koppling till andra objekt. Som exempel nämndes tidigare ”träd med många äpplen” eller ”på vägen fanns många bilar”. Hur ska detta hanteras? Med tanke på kursobjektet Course så faller det sig naturligt att varje kurs har en lärare, Teacher. Hur denna koppling kan ordnas ses i följande bild. Viktiga egenskaper hos en lärare ses till vänster där Teacher visas som ett eget objekt. Teacher har fått egenskaperna namn som Name, lärarens signatur som TeacherCode, och lärarens epost som Email. Mellan objekten i ritningen finns en linje med siffran ett vid Teacher. Det betyder att på varje kurs finns det exakt en lärare, inte flera. Om det hade funnits två lärare så skulle detta visas med siffran två i ritningen o.s.v. Att siffrans placering är bredvid objektet Teacher i ritningen betyder att läraren tillhör kursen. Course

Name Code Points Start End

Teacher

Name TeacherCode Email

1

IsActive En kurs måste så klart också ha elever. Det kan också ordnas, se nedan. Ett nytt objekt Student har ritats till höger. Varje elev har ett namn som Name, en klass som Class och en epostadress som Email. Det kan finnas många elever, d.v.s. ett odefinierat flertal, på varje kurs, vilket visas genom en asterisk (*) vid Student på linjen som binder ihop objekten. Asterisken är placerad bredvid Student-objektet vilket betyder att eleverna tillhör kursen. Course Teacher

168

Name TeacherCode Email

1

Name Code Points Start End

Student

*

Name Class Email

IsActive Exemplet visar att vissa objekt kan agera som hållare för andra objekt. En kurs har en lärare och många elever. Det går alltså utmärkt bra att modellera saker som har kopplingar till varandra eller saker som består av andra saker. T.ex. ”en lärare på varje kurs” eller ”träd med många äpplen”.

Övning 11.1 Du har fått i uppdrag att i framtiden göra ett program som kan hantera många böcker för ett bibliotek. Varje bok i biblioteket måste ha titel, författare, förlag (d.v.s. det företag som publicerar boken), upplaga, publiceringsår och antal sidor. Varje bok måste kunna visa omslagssidor (fram och bak) men också exempelsidor från bokens innehåll. Arbeta objektorienterat och rita ett objekt som representerar en bok. (Du kan använda papper och penna eller ett enkelt ritprogram.)

51108445.1.1_inlaga.indd 168

2022-03-23 13:32


Efter att ha ritat och visat upp ditt bokobjekt på ett möte säger din uppdragsgivare att varje bok kan ha flera författare och att varje författare har ett namn, telefonnummer och en epostadress. Varje bok har också ett förlag. Det kan dock bara finnas ett förlag per bok. Alla förlag har ett namn, telefonnummer och en e-postadress. Gör om din ritning från övning 11.1 rita in många författare och ett förlag.

11.2 Objekt på praktisk nivå Nu när det är klart vad objekt är och hur objekt används för att modellera saker och föremål är det dags att omvandla objekt till något som är användbart i ett programmeringsspråk. Då behövs fyra nya begrepp. Dessa är klass, klassdiagram, klassdefinition och instans.

11. Objekt och objektorientering.

Övning 11.2

Klasser från objekt Begreppet klass är nästan identiskt med begreppet objekt förutom att klasser har en koppling till ett visst programmeringsspråk. Objekt har ingen sådan koppling utan är helt och hållet definierade på konceptuell nivå. När en klass skapas används korresponderande objekt som förebild. Klasser är som objekt förutom att de inte har egenskaper och förmågor som objekt utan istället har klasser medlemsvariabler och metoder. Se bild. Alternativt kan detta sägas att ett objekt blir till en klass när objektets egenskaper och förmågor översätts med hjälp programmeringstekniska begrepp som medlemsvariabler och metoder. Objekt

Klass

Egenskaper

Medlemsvariabler

Förmågor

Metoder

Kommunikation

Händelser

I praktiken är det vanligt att klasser används på konceptuell nivå istället för objekt. Ritningar på alla klasser som behövs i ett program kallas för klassdiagram. Det klass­ diagram som fås när objektet Course översätts till en klass med hjälp av C# ses i bilden nedan. I C# definieras variabler med både namn och datatyp. Detta visas i klassdiagrammet genom att skriva variabelnamn, semikolon och sedan datatyp. Framför varje medlemsvariabel finns ett plustecken som anger att variabelns åtkomlighet är publik. Mer om detta senare. Första bokstaven hos namnen för varje medlemsvariabel skrivs med stor bokstav. Denna regel styrs av de kodkonventioner som Microsoft rekommenderar för C#. Datatyp anges sist, Name och Code är strängar, Points är heltal, och Start och End är datum. Längst ner hittas en metod med namnet IsActive som tar ett ingångsargument av typen tidpunkt. Vi kan se att metoden kommer att returnera ett Course svar av typen boolesk d.v.s. sant eller falskt. Denna + Name: string metod kontrollerar troligen om en viss angiven tid+ Code: string punkt ligger mellan kursens Start och Slut, d.v.s. + Points: int om kursen är aktiv. + Start: datetime + End: datetime

169

+ IsActive(datetime): bool

51108445.1.1_inlaga.indd 169

2022-03-23 13:32


11. Objekt och objektorientering.

Klassdiagram – Ritningar av klasser Begreppet klass är alltså nästan identiskt med begreppet objekt förutom att klasser har en koppling till ett utvalt programmeringsspråk. I bilden nedan har ritningen med de kopplade objekten kurs med lärare och elever gjorts om till klasser i ett klassdiagram för C#. Course Teacher

+ Name: string + TeacherCode: string + Email: string

1

+ Name: string + Code: string + Points: int + Start: datetime + End: datetime + Teacher: Teacher + Students: List<Student>

Student

*

+ Name: string + Class: string + Email: string

+ IsActive(datetime): bool En stor skillnad mellan objektet Course och klassen Course är att klassen har två extra medlemsvariabler. På klassnivå i praktiken med ett programkod är detta nödvändigt för att kursen ska kunna hålla en lärare och många elever. I diagrammet ses att den nya variabeln Teacher som lagrar kursens lärare har klassen Teacher som datatyp. Egendefinierade klasser kan alltså användas som datatyper i andra klasser. För att hålla kursens alla elever finns en variabel Students, med pluralis-s för det kan finnas många elever, med datatypen List<Student> som klarar av att hantera många elever. List är en kollektionsklass som finns i C#. Istället för en lista hade också en lösning med vanlig fältvariabel enligt Students: Student[] kunnat fungera men nackdelen med att göra så är att fältets storlek i så fall måste anges i förväg inuti hakparenteserna.

Klassdefinitioner – att skriva kod

170

51108445.1.1_inlaga.indd 170

Nästa steg från objekt till programkod är att översätta klasser från ritade klassdiagram till ett format som ditt programmeringsspråk förstår. Detta görs med s.k. klassdefinitioner på speciella platser i programkoden. En del av klassdefinitionen för Course ses nedan. I C# används det reserverade ordet class och här definieras klassens medlemsvariabler, metoder och händelser med datatyper, regler och syntax som är giltiga för C#. För varje egenutvecklad typ av klass som används av programmet måste en unik klassdefinition skrivas vilket betyder att för vårt exempel ovan så måste definitioner för Teacher och Student också skrivas.

2022-03-23 13:32


11. Objekt och objektorientering.

class Course { public string Name; public string Code; public int Points; public DateTime Start; public DateTime End; public bool IsActive(DateTime inDate) { if (inDate > Start && inDate < End) { return true; } else { return false; } } }

Instanser Genom klassdefinitionen ”vet” C# hur klassen ser ut och nu kan instanser göras med programkod. En instans är en separat kopia med data som använder klassen som prototyp. Hur många instanser som helst kan göras och utnyttjas av ett program. I bilden visas två instanser av klassen Course, båda är olika för de representerar olika kurser men följer ändå av samma mall som definierats av klassen Course som i sin tur byggde på objektet Course. Båda instanserna har sitt eget namn, sin egen kurskod, detsamma med poäng, startdatum och slutdatum. All data som programmet behöver kan lagras i instanser. Dessa kan i sin tur kan användas för det som programmet är tänkt att göra, kanske utföra beräkningar eller visa resultat på grafiskt gränssnitt o.s.v.

Course

”Kemi 1” ”KEMKEM01” 100 16 aug 2021 10:00 13 jun 2022 10:59 Course

”Matematik 4” ”MATMAT04” 100 18 aug 2021 14:00 14 jun 2022 08:59

171

Övning 11.3 Gör om din ritning av objekt från övning 11.2 om böcker i ett bibliotek till ett klassdiagram. Ritningen visade att ett bokobjekt kunde ha många författareobjekt men bara ett förlagsobjekt.

51108445.1.1_inlaga.indd 171

2022-03-23 13:32


11. Objekt och objektorientering.

11.3 Klasser med C# och Visual Studio Att göra en klassdefinition i C# är enkelt. Starta Visual Studio och skapa ett nytt Windows Forms-projekt (av typen Net Framework) och välj Framework 4.7.2 eller högre. Namnge det nya projektet som CourseApp. Gå in i Solution Explorer och döp om projektets form från Form1 till FrmCourseApp. Klicka på yes om Visual ­Studio vill döpa om alla referenser av Form1. Högerklicka till sist på projektfilen, välj Add och sedan Class. Ett nytt fönster öppnas. Här kan nya saker adderas till ett C#-projekt i Visual Studio. Välj Class, ge filen namnet Course.cs och klicka på Add.

Nu finns en ny ikon i Solution Explorer med namnet Course.cs. Detsamma gäller för mappen där projektets filer sparas på datorn. Detta kan kontrolleras med Windows filsystem. Det är alltid möjligt att hitta var projektfilerna finns på datorn genom att klicka på ikonen för projektet i Solution Explorer och undersöka värdet för egenskapen Project Folder. Alla klassfiler som görs med C# i Visual Studio kommer att ha filändelsen .cs.

172

En viktig sak att komma ihåg är att varje cs-fil i princip kan innehålla flera klassdefinitioner. Det betyder att i filen Course.cs skulle det kunna finnas definitioner för fler klasser än bara Course som t.ex. Teacher och Student, d.v.s. flera klasser i samma cs-fil är fullt möjligt. Ett tips för tydlighetens skull är därför att alltid göra en ny cs-fil för varje ny klass. Klicka på din nya fil Course.cs i Solution Explorer. Då öppnas ett fönster med följande kod: namespace CourseApp { class Course { } }

51108445.1.1_inlaga.indd 172

2022-03-23 13:32


Course

+ Name: string + Code: string + Points: int + Start: datetime + End: datetime + IsActive(datetime): bool

Synlighet med åtkomstmodifierare I C# skapas variabler allmänt genom att först ange datatypen och sedan variabelns namn. Detsamma gäller för medlemsvariabler förutom att synlighet måste anges med hjälp av kodordet public. Om detta görs för den första egenskapen Name hos klassen Course så fås en början på en klassdefinition som visas i bilden nedan. Namnet för variabeln är alltså Name, datatypen är string och synligheten är public.

11. Objekt och objektorientering.

Här ses att en ny klass definieras i C# med med hjälp av det reserverade ordet class och den nya klassens namn. Innanför klamrarna är det meningen att programmeraren ska skriva hur klassen ska se ut. Uppgiften är alltså att översätta ritningen av en klass som syns till höger till kod mellan klamrarna i bilden som syns ovan för att göra en klassdefinition i C#.

namespace CourseApp { class Course { public string Name; } }

Begreppet synlighet eller åtkomst används inom objektorienterade språk för att begränsa tillgången till skyddade tillämpningar av programmets metoder och objekt. T.ex. kan det vara bra att klassen kund är tillgängligt överallt i programmet men den kod som räknar ut om en viss kund är ”bonuskund” och därför får rabatter på alla inköp bör kanske bara få finnas i en skyddad metod som tillhör själva kundklassen. Det betyder att känslig kod som ändrar beteendet för alla instanser av kunder bara får skrivas inuti själva kundklassen och inte i andra delar av programmet. Åtkomst handlar alltså om vilka delar av programmets kod som är tillgänglig från kod i andra ställen av programmet. Detta styrs med hjälp av s.k. åtkomstmodifierare. Det finns många olika sorters modifierare men de viktigaste som är intressanta här är public, vilket betyder att en medlemsvariabel är tillgänglig överallt, och private som gör att en medlemsvariabel bara är åtkomlig i kod från samma klass. En tredje variant är internal vilket betyder åtkomst endast från samma assembly, d.v.s. nästan som public men egentligen bara åtkomst för komponenter inom samma Visual Studio-projekt.

173

Om en åtkomstmodifierare inte anges använder C# förvalda värden. T.ex. i bilden ovan saknas modifierare framför ordet class, det står bara class Course. Den förvalda modifieraren för en klass är internal i C# medan det förvalda värdet för en medlemsvariabel i en klass är private. Det betyder att att vår nya klass Course endast är publikt synlig inom projektet och om vi bara skrivit string Name; i koden ovan så hade denna medlemsvariabel automatiskt fått modifieraren private.

51108445.1.1_inlaga.indd 173

2022-03-23 13:32


11. Objekt och objektorientering.

Om ritningen på objektet Course fullständigt översätts med C#kod fås följande klassdefinition med alla medlemsvariabler och en metod. Observera att från ritningen av klassen Course fås bara signaturen av metoden IsActive. Med metodens signatur menas namn, ingångsargument och returvärde. Själva implementationen av metoden, d.v.s. exakt hur IsActive ska fungera, måste skrivas med kod i klassdefinitionen för Course.

Course

+ Name: string + Code: string + Points: int + Start: datetime + End: datetime + IsActive(datetime): bool

class Course { public string Name; public string Code; public int Points; public DateTime Start; public DateTime End; public bool IsActive(DateTime inDate) { if (inDate > Start && inDate < End) { return true; } else { return false; } } }

Övning 11.4 Gör ett nytt windows form-projekt som beskrivs i texten ovan. Lägg till en klass och skriv klassdefinitionen för Course som visas ovan.

174 Konstruktormetoder För att prova att allt fungerar, skriv klassdefinitionen som visas här ovan. Spara och klicka på Build i menyn längst upp i Visual Studio och sedan på Build Solution. Om inga fel visas är den nya klassen klar att användas. Högerklicka på projektets form i Solution Explorer och välj view code. (Om projektets form inte har fått namnet FrmCourseApp så kommer denna fil att ha det förvalda namnet Form1.cs.) Då öppnas klassdefinitionen för formen. Jo det stämmer, den form d.v.s. det grafiska fönster, som visas när ett projekt i Visual Studio körs är också en klass i C# och skrivs i en cs-fil precis på samma sätt som klassen Course. I denna cs-fil står det dock lite mer, nämligen public partial class frmCourseApp : Form. Här har Visual Studio använt modifieraren public medan ordet partial betyder att hela klassdefinitionen finns uppdelad på flera olika cs-filer. Visual Studio gör så ibland. Det kryptiska frmCourseApp : Form betyder att klassen frmCourseApp ärvs från en mer generell klass som heter Form.

51108445.1.1_inlaga.indd 174

2022-03-23 13:32


public partial class FrmCourseApp : Form { public FrmCourseApp() { InitializeComponent(); } }

11. Objekt och objektorientering.

Vidare ses att i klassdefinitionen för formen finns en metod med exakt samma namn som klassen har. Detta är klassens konstruktormetod som automatiskt exekveras en gång när en instans av klassen skapas. Alla klasser har metoder av denna typ också vår Course klass även om vi inte skrivit någon speciell konstruktor för Course. Det beror på att Visual Studio automatiskt lägger till en s.k. default constructor utan innehåll vid exekvering om en sådan inte skrivits och därför saknas i klassdefinitionen.

Tanken bakom konstruktormetoder är att här ska det finnas kod som behövs när en instans av klassen skapas. Vi kan se ett exempel på det i bilden ovan. När formklassen, som ger ett grafiskt fönster på skärmen, skapas körs en metod som heter InitializeComponent av formens konstruktor. Högerklicka på denna metod och välj Go to Definition. Nu visas en annan fil i Solution Explorer som heter FrmCourseApp. Designer.cs och där hittas fortsättningen av klassdefinitionen för FrmCourseApp. Här visas också att metoden InitializeComponent definierar och konfigurerar grafiska komponenter. Varje gång en knapp eller textruta läggs till genom att klicka och dra ut komponenten på formen med Visual Studios grafiska editor så skrivs kod automatiskt i denna metod. Det kan man se eftersom det står #region Windows Form Designer generated code några rader längre upp i filen. Denna kod kommer att köras en gång när formen skapas eftersom InitializeComponent anropas från formens konstruktor och konstruktorn körs bara en gång då formen skapas.

Instansiera klassen Course Då är det dags att göra en instans, d.v.s. en kopia, av klassen Course. Med C# görs detta med hjälp av operatorn new. Gör ett snabbt experiment. Gå in i formklassen på raden ovanför konstruktorn och skriv new Course() direkt följt av en punkt. Då ska Visual Studios intellisense visa en lista med de medlemsvariabler och metoder som finns för Course. Detta försök visar att med hjälp av operatorn new, klassens namn och två parenteser skapas direkt en instans d.v.s. en ny kopia av klassen Course. För att ha någon nytta av en instans behövs dock en medlemsvariabel i form­klassen annars är instansen inte åtkomlig. Det betyder att tre saker måste göras i koden, skapa en ny medlemsvariabel, skapa en instans av klassen Course och till sist tilldela instansen till variabeln. Allt detta går att göra på en enda rad som visas nedan.

175

public partial class FrmCourseApp : Form { Course MyCourse = new Course(); public FrmCourseApp() {

Medlemsvariabeln som behövs skrivs i formklassen innan konstruktorn. Datatypen Course används tillsammans med ett påhittat variabelnamn, t.ex. MyCourse. En ny instans skapas med operatorn new och klassens namn, direkt följt av parenteser (som betyder att klassens default constructor körs). Den nya instansen kopplas till variabeln

51108445.1.1_inlaga.indd 175

2022-03-23 13:32


11. Objekt och objektorientering.

MyCourse med ett lika med tecken. På tekniskt fackspråk heter det att medlems­ variabeln MyCourse har deklarerats och initieras med en instans av klassen Course. Exakt samma regler gäller här som i klassdefinitionen för de publika medlemsvariablerna i Course. Så kom ihåg, eftersom ingen synlighet angetts i detta fall så kommer åtkomsten till MyCourse att vara förvalt private, d.v.s. bara åtkomlig från kod inifrån formklassen.

Egna metoder för datahantering Nu har programmet en instans av klassen Course, d.v.s. en kopia med åtkomst genom en medlemsvariabel i klassen FrmCourseApp men kopian är helt tom, ingen av instansens medlemsvariabler innehåller någon data. Nästa sak att fundera på är därför datahantering. Redan nu är det klart att detta kommer att vara viktigt vid minst två olika tillfällen. Först då instanser fylls med data från någon datakälla men även åt andra hållet då data från instanserna ska visas för programmets användare. För att hantera detta är det lämpligt att skriva två helt nya egna metoder i FrmCourseApp. En väl etablerad regel inom programmering är att varje enskild metod som skrivs bara ska ha en enda uppgift. Om denna regel inte strikt följs från början blir ett program till sist omöjligt att överblicka och underhålla. D.v.s. det är inte bra om en och samma metod kanske först kontaktar databasen, sedan beräknar data och till sist ändrar i textboxar i det grafiska gränssnittet. Det är mycket bättre dela upp koden med separata metoder där var och en utför sin speciella uppgift. I vårt fall behövs en metod för att fylla instanser med data och en annan metod för att visa instansernas data på något annat sätt t.ex. i det grafiska gränssnittet. Var ska anropen till dessa metoder placeras i formklassen FrmCourseApp? Ett bra ställe är i konstruktorn efter InitializeComponent av två orsaker. För det första så kommer konstruktorn alltid att köras en gång då programmet startar och formen visas. Om det finns anrop till andra metoder här så kommer dessa också att exekveras. D.v.s. LoadData och ShowData kommer att köras då programmet startar vilket är precis vad vi vill. Om anropen sker efter InitializeComponent är vi dessutom säkra på att formens alla grafiska komponenter är på plats när det är dags att hämta och visa data. Gör därför två nya metoder (som inte returnerar något d.v.s. med returtypen void), LoadData och ShowData som anropas från konstruktorn i FrmCourseApp enligt bild. Course MyCourse = new Course();

176

public FrmCourseApp() { InitializeComponent(); LoadData(); ShowData(); } void LoadData() { } void ShowData() { }

51108445.1.1_inlaga.indd 176

2022-03-23 13:32


I metoden LoadData kommer fokus att vara på att fylla instanser med data, nu först i detta exempel bara för en enda instans av klassen Course men i framtiden skulle det kunna vara möjligt att skriva kod för hämta data till tusentals instanser från t.ex. sparade datafiler eller till och med databaser. Skriv MyCourse och en punkt mellan måsvinge-parenteserna i metoden LoadData. Då ska Visual Studios intellisense visa en lista med de medlemsvariabler och metoder som finns för Course. Se bild. Här visas med symboler i blått de medlemsvariabler som skrevs i klassdefinitionen för Course. De metoder som klassen har visas som vita kuber med lila kanter. Metoden IsActive känns igen medan de andra metoderna kommer från att Course ärver från en överordnad klass som heter Object. Alla klasser i C# ärver från Object och därför har alla klasser tillgång till de metoder som Object definierar. Välj Name ur listan och skriv lika-med-tecken och strängen "Kemi 1" och semikolon. Gör ny rad och samma sak med Code o.s.v. som visas i koden nedan. På detta sätt kan värden för alla medlemsvariabler tilldelas. I detta exempel hårdkodas påhittad data in i instansen men tillvägagångssättet för datahämtning med verklig data är exakt samma. När alla medlemsvariabler fått ett värde är instansen fylld med data och klar att användas av kod i andra delar av programmet.

11. Objekt och objektorientering.

Fyll instanser med data

void LoadData() { MyCourse.Name = "Kemi 1"; MyCourse.Code = "KEMKEM01"; MyCourse.Points = 100; MyCourse.Start = DateTime.Parse("2021-08-16"); MyCourse.End = DateTime.Parse("2022-06-13"); }

Kan medlemsvariabeln med den nya instansen användas varsomhelst? Nej, det finns vissa regler som måste följas, t.ex. får inte tilldelning, som ses i bilden, ske direkt i klassen. Då fås ett felmeddelande av Visual Studio. Det beror på att inuti en klass får det bara finnas medlemsvariabler och metoder. I C# Programming Guide hittas en komplett lista på vad som är tillåtet att skriva här.

177

Hämta data från en instans Upptäcktsfärden om praktisk objektorientering med C# börjar närma sig sitt slut. Den sista pusselbiten som behövs är hur data hämtas från en instans. En speciell metod ShowData har redan förberetts för detta ändamål. Här kommer den data som finns i programmets enda instans att skrivas ut för en kontroll att allt fungerar som det ska. För att klara detta på ett enkelt sätt utan att använda debuggern och breakpoints används klassen Debug som har många metoder för felsökning, däribland en Print-metod. Allt som skrivs ut med Debug.Print hamnar i output-fönstret i Visual Studio när programmet körs. Det fulla namnet för denna klass är System. Diagnostics.Debug där System.Diagnostics är namn på namespaces och

51108445.1.1_inlaga.indd 177

2022-03-23 13:32


11. Objekt och objektorientering.

Debug är en s.k. statisk klass. I C# används namespaces för att organisera innehåll och med hjälp av direktivet using behöver inte fullständiga klassnamn alltid skrivas ut. Lägg därför till raden using System.Diagnostics längst upp i FrmCourseApp så kommer Debug-klassen bli lite enklare att använda. Då räcker det att skriva Debug.Print. En bra sak att känna till är att using-direktiv som visas med ljusblå och grå textfärg betyder att inga klasser från dessa namespaces används av koden i aktuell fil och därför kan dessa using-direktiv tas bort ur listan. Som nämnts innan är Debug en statisk klass. Det speciella med denna typ av klasser är att det inte går att göra instanser av dem. Istället används klassnamnet direkt för att få tag på klassens metoder. Detta är användbart om det finns många generella metoder som används inom samma område. T.ex. genom att skriva Math och en punkt så fås alla möjliga matematiska funktioner som kan användas i C#. Klassen Math, precis som Debug, är alltså statiska klasser.

using using using using

System; System.Diagnostics; System.Collections.Generic; System.ComponentModel;

För att hämta och skriva ut data i output-fönstret används återigen medlemsvariabeln MyCourse. T.ex. hämtas instansens namn genom att skriva MyCourse.Name. På samma sätt hämtas data för de andra medlemsvariablerna.

void ShowData() { Debug.Print("Data in Instance"); Debug.Print("Name: " + MyCourse.Name); Debug.Print("Code: " + MyCourse.Code); Debug.Print("Points: " + MyCourse.Points.ToString()); Debug.Print("Start: " + MyCourse.Start.ToShortDateString()); Debug.Print("Name: " + MyCourse.End.ToShortDateString()); }

178

En del variabler måste typomvandlas till strängar, t.ex. Points som är ett heltal med hjälp av metoden ToString() och tidpunktsvariablerna till korta datum utan tidsangivelse med ToShortDateString(). Observera att varje anrop med Debug. Print ger en ny rad i utskriften. Bygg och kör programmet. Om inga felmeddelande dyker upp kommer följande visas i output-fönstret i Visual Studio. I output-fönstret visas att det går utmärkt att få ut data från den instans vi har.

51108445.1.1_inlaga.indd 178

2022-03-23 13:32


Övning 11.5 Fortsätt ditt projekt från övning 11.4 enligt vad som beskrivs i texten ovan. När du är klar ska instansens data visa i output-fönstret som visas på bilden ovan.

11. Objekt och objektorientering.

Nu är genomgången om objekt på praktisk nivå klar med alla de moment som behövs för att jobba objektorienterat med C#. Dessa är viktiga att lägga på minnet eftersom samma sekvens kommer att upprepa sig varje gång arbete utförs med objekt, klasser och instanser. Tänk på att innan programkod ens skrivs är det viktigt att analysera vilka uppgifter och problem som programmet ska lösa. Modellera lösningar genom att identifiera viktiga objekt, hur dessa är kopplade till varandra och bestäm vilka egenskaper och förmågor som objekten ska ha. Omvandla sedan objekten till klasser i ett klassdiagram. Skriv sedan klassdefinitioner och gör instanser med ditt programmeringsspråk. Använd till sist instanserna för den data som programmet ska hämta och visa.

11.4 Förbättringar av programmet I en verklig tillämpning som använder en yttre datakälla som t.ex. en databas är det möjligt att applikationen hanterar tusentals instanser samtidigt i programmets minne. Dessa Iaddas ofta helt eller delvis i samband med att applikationen startar. För det omvända gäller samma sak, när applikationen stängs är det viktigt att nyskapade instanser och instanser vars data har ändrats under den tid programmet körts skrivs ner till databasen. För att klara av detta är det vanligt att ha dedikerade metoder i koden som uteslutande jobbar med att antingen läsa in data och skapa instanser eller tvärtom ta data från instanser och föra över till yttre datakällor. I exemplet ovan är detta redan förberett eftersom programmet utnyttjade metoderna LoadData och ShowData. Vi kan fortsätta att utveckla vårt exempel en liten bit till genom att skriva om koden i programmet för att hantera många kurser, d.v.s. många instanser, och använda ett grafiskt gränssnitt för att visa data. De förändringar som krävs kommer framförallt ske i metoderna LoadData och ShowData.

Många kurser För att programmet ska kunna kunna jobba med många kurser måste MyCourse bytas ut eftersom denna variabel bara kan peka på en enda instans. Som tidigare nämnts går det bra att använda fält med klasser, t.ex. är uttrycket Course[] MyCourseArray = new Course[100]; giltigt men som innan är problemet att fältets storlek måste anges i förväg. Här finns bara plats för hundra instanser. En bättre lösning är att använda en av de kollektionsklasser som finns inbyggda i C#. Finessen med dessa är att storleken på listan anpassas automatiskt, ökar eller minskar, efter hur många instanser som behöver hanteras. Sudda därför ut den gamla medlemsvariabeln MyCourse och ersätt med raden List<Course> MyCourseList = new List<Course>(); på samma ställe i koden. Observera att List är en strongly typed collection vilket betyder att den datatyp som listan ska hålla måste anges i förväg. Det görs mellan < och > tecknen.

179

List<Course> MyCourseList = new List<Course>();

51108445.1.1_inlaga.indd 179

2022-03-23 13:32


11. Objekt och objektorientering.

Nu när MyCourse har bytts ut mot MyCourseList krävs flera nya moment i koden för LoadData som inte behövdes innan. I LoadData ska nu nya instanser skapas. De ska fyllas med data och till sist ska den nya instansen adderas till MyCourseList. Detta kan göras på olika sätt. Ett första visas nedan.

void LoadData() { // *** Working with List() class, First Optional Way *** MyCourseList.Add(new Course()); MyCourseList[0].Name = "Kemi1"; MyCourseList[0].Code = "KEMKEM01"; MyCourseList[0].Points = 100; MyCourseList[0].Start = DateTime.Parse("2021-08-16"); MyCourseList[0].End = DateTime.Parse("2022-06-13"); MyCourseList.Add(new Course()); MyCourseList[1].Name = "Matematik1"; MyCourseList[1].Code = "MATMAT01"; MyCourseList[1].Points = 100; MyCourseList[1].Start = DateTime.Parse("2021-08-11"); MyCourseList[1].End = DateTime.Parse("2022-06-10");

För att lägga till en ny instans av Course till listan hos MyCourseList används metoden Add som kommer ifrån List<>-klassen. En ny instans skapas som innan med hjälp av operatorn new. Båda momenten utförs samtidigt på första raden genom att skriva MyCourseList.Add(new Course());.

180

Nu finns en tom instans av Course utan data på listans första plats. För att komma åt olika positioner i listan (List<>-klassen) kan index användas precis som med ”vanliga” fältvariabler. Med uttrycket MyCourseList[0] fås åtkomst till den instans som finns lagrad på första platsen i listan (eftersom att i C# startar alla index med noll.) Detta kombineras med de medlemsvariabler som Course-klassen har så att med uttrycket MyCourseList[0].Name fås tillgång till listans första instans värde på variabeln Name. På detta sätt kan Course-instansens medlemsvariabler fyllas med data på de efterföljande raderna. Listans Add-metod används återigen på rad sju och data för en ny instans på position MyCourseList[1] matas in. Denna procedur kan upprepas om och om igen. Tänkbara problem med detta tillvägagångssätt är att försök till åtkomst av positioner i listan som inte finns, d.v.s. om ett felaktigt index används fås troligen ett körtidsfel i stil med index out of bounds. Det finns också ett annat sätt att fylla listan med instanser. Detta visas nedan. Här skapas först en instans av Course som sedan fylls med data på vanligt sätt. Till sist används List<>-klassens Add-metod. Observera att eftersom variabeln tmpCourse deklareras längst upp behövs den inte deklareras igen på rad åtta. Däremot är det viktigt att variabeln tilldelas en ny instans på rad åtta, med operatorn new, annars skrivs samma data över gång på gång.

51108445.1.1_inlaga.indd 180

2022-03-23 13:32


tmpCourse = new Course(); tmpCourse.Name = "Webbutveckling1"; tmpCourse.Code = "WEBWEB01"; tmpCourse.Points = 100; tmpCourse.Start = DateTime.Parse("2021-08-19"); tmpCourse.End = DateTime.Parse("2022-06-17"); MyCourseList.Add(tmpCourse);

11. Objekt och objektorientering.

// *** Working with List() class, Second Optional Way *** Course tmpCourse = new Course(); tmpCourse.Name = "Matematik4"; tmpCourse.Code = "MATMAT04"; tmpCourse.Points = 100; tmpCourse.Start = DateTime.Parse("2018-08-17"); tmpCourse.End = DateTime.Parse("2019-06-15"); MyCourseList.Add(tmpCourse);

Grafiskt gränssnitt I det grafiska gränssnittet behövs textboxar och etiketter till alla egenskaper som Course har och dessutom en listbox för att visa alla instanser som laddas i LoadData. En etikett för att visa om kursen är aktiv krävs också. Alla komponenter som behövs och deras namn visas nedan.

51108445.1.1_inlaga.indd 181

Kontroll

Namn

GroupBox

GrpCourse

Label

LblName

TextBox

TxtName

Label

LblCode

TextBox

TxtCode

Label

LblPoints

TextBox

TxtPoints

Label

LblStart

Kontroll

Namn

TextBox

TxtStart

Label

LblEnd

TextBox

TxtEnd

Label

LblIsActive

Label

LblActiveResult

ListBox

LbxCourses

Label

LblCourses

181

2022-03-23 13:32


11. Objekt och objektorientering.

Namn på komponenter i det grafiska gränssnittet ska alltid döpas om till namn som visar vad de används till. Det får inte finnas några TextBox1 och TextBox2 o.s.v. i ett färdigt program. Det är frivilligt att använda namnen i tabellerna ovan. För­ delen om detta görs är att bokens kodexempel kommer kunna användas direkt utan kompileringsfel. När programmet startar ska listboxen LbxCourses fyllas med namnen på de kurser som finns lagrade i MyCourseList. All data om den i listboxen överst placerade kursen visas initialt i textboxarna till vänster. Om kursen är aktiv nu visas en grön markering annars röd. Om användaren klickar på ett annat kursnamn i listan visas data för denna kurs. Med de förbättringar som hittills nämnts kommer koden i FrmCourseApp att få följande utseende. Kom ihåg att formens konstruktor körs bara en gång då programmet startar så att efter InitializeComponent() så anropas LoadData() med de ändringar i koden som beskrivits i stycket ovan. När LoadData() är klar finns data om alla kurser lagrade som instanser i MyCourseList.

public partial class FrmCourseApp : Form { List<Course> MyCourseList = new List<Course>(); public FrmCourseApp() { InitializeComponent(); LoadData(); ShowDataInListBox(); ShowData(0); }

Fyll listboxen med data

182

Efter LoadData() när programmet har all data är nästa steg att fylla listboxen med kursnamnet för de instanser som finns. För att klara detta behövs en dedikerad metod, ShowDataInListBox(), som skrivs i formklassen. Observera att den här metoden körs endast då formen visas för första gången. Som vanligt när det gäller metoder som hanterar grafiska komponenter saknas ingångsargument och retur­ typen är void. Syftet är bara manipulera komponenters egenskaper på olika sätt.

void ShowDataInListBox() { LbxCourses.Items.Clear(); foreach (Course item in MyCourseList) { LbxCourses.Items.Add(item.Name); } LbxCourses.SelectedIndex = 0; }

51108445.1.1_inlaga.indd 182

2022-03-23 13:32


Klick i listboxen När användaren klickar på en post i listboxen ska data för vald kurs visas. Dubbelklicka på listboxen på formen så fås en händelsehanterare automatiskt. Händelsen vi vill skriva kod för är listboxens SelectedIndexChanged.

11. Objekt och objektorientering.

Koden i metoden kan tolkas på följande vis. Först töms listboxen på poster med raden LbxCourses.Items.Clear();. Hos en listbox hittas varje post i den visade listan i kollektionen Items. På nästa rad så loopas innehållet i MyCourseList igenom, alla Course-instanser, från början till slut med hjälp av en foreach-slinga. Observera att varje item typomvandlas till Course av slingan vilket betyder att listboxens Items. Add-metod tar en sträng som ingångsargument. Här anges kursens namn, item. Name, som är en sträng. Detta betyder att när loopen är klar så är det en lista på alla kursers namn som kommer att visas i listboxen. (I princip skulle item.Code eller någon annan egenskap kunnat väljas istället.) På sista raden väljs listboxens första post ut. Skriv koden ovan och kontrollera att allt fungerar.

private void LbxCourses_SelectedIndexChanged(object sender, EventArgs e) { ShowData(LbxCourses.SelectedIndex); }

Ordningsnumret för den kurs som användaren klickar på i listan kommer att ges av LbxCourses.SelectedIndex så detta värde skickas vidare som ingångsargument till metoden ShowData() som i sin tur har i uppgift att visa kursens data. void ShowData(int inIndex) { TxtName.Text = MyCourseList[inIndex].Name; TxtCode.Text = MyCourseList[inIndex].Code; TxtPoints.Text = MyCourseList[inIndex].Points.ToString(); TxtStart.Text = MyCourseList[inIndex].Start.ToShortDateString(); TxtEnd.Text = MyCourseList[inIndex].End.ToShortDateString(); if (MyCourseList[inIndex].IsActive(DateTime.Now)) { LblActiveResult.BackColor = Color.Green; } else { LblActiveResult.BackColor = Color.Red; }

183

}

Metoden ShowData() byggs om för att ta emot ett ingångsargument i form av ett heltal som används för att peka ut rätt instans i MyCourseList genom den indexhantering som finns tillgänglig i List<>-klassen. Med raden TxtName.Text = MyCourseList[inIndex].Name; skrivs alltså namnet för en viss instans av Course ut i textboxen som heter TxtName. Med den avslutande if-satsen kontrolleras om den utvalda kursinstansen är aktiv just nu. Resultatet visas med färgerna grön eller röd på GUI.

51108445.1.1_inlaga.indd 183

2022-03-23 13:32


11. Objekt och objektorientering.

Övning 11.6 Fortsätt ditt projekt från övning 11.5 enligt vad som beskrivs i texten ovan. När du är klar ska instansens data visas i formens grafiska gränssnitt som ovan.

Övning 11.7 Skriv ett program där man kan registrera skyttar i en pistolskyttetävling med namn och poäng. Det ska finnas en klass och en ToString-metod. Varje instans läggs till en listbox, så att listboxen får använda klassens ToString-metod för att visa rätt text.

Övning 11.8 Skriv ett program där man kan registrera löppass. Det ska finnas en klass som innehåller sträcka och tid. Det ska också finnas en metod eller egenskap som beräknar och returnerar instansens hastighet. Fönstret kan visa löploggen med eller utan hastighet.

184

51108445.1.1_inlaga.indd 184

2022-03-23 13:32



Programmering 1 C# Den här boken riktar sig mot nybörjaren i programmering. Det krävs inga förkunskaper annat än lite datorvana för att kunna installera nödvändig programvara. Det finns gratis programvara som kan användas för att arbeta med boken t.ex. Visual Studio Community 2022. Boken är främst avsedd att användas som kurslitteratur till gymnasiekursen Programmering 1. Boken kan också vara till god hjälp för den som vill lära sig programmering på egen hand. Detta är andra upplagan och den har uppdaterats för att bättre svara mot förändringar i kursplanerna. Boken har också kompletterats med några större projektuppgifter för de elever som är betjänta av att ibland jobba mer projektinriktat med lite större program. Extra lärarmaterial finns som lärarwebb. Extramaterialet består av färdiga programfiler till samtliga exempel, övningar och uppgifter, provförslag m.m. och kan hämtas digitalt. Det kan bespara läraren en hel del arbete med att förbereda presentationer eller demonstrationer av bokens innehåll. Författare till Programmering 1 C# är Magnus Lilja, Ulrik Nilsson och Dennis Berling. Alla tre har mång­årig erfarenhet av att undervisa i programmering.

ISBN 9789151108445

9 789151 108445

51108445.1.1_omslag.indd 4

2022-03-23 13:06


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.