Difference between revisions of "CSharp Classes"

From Teknologisk videncenter
Jump to: navigation, search
(Inheritance)
(Inheritance)
Line 244: Line 244:
 
         Console.WriteLine(e1.Hold);
 
         Console.WriteLine(e1.Hold);
  
Bemærk at vi opretter e1 med fornavn og efternavn som egentlig hører til Person og hold som kun anvendes af Elev. Selv om det er en elev kan vi stadig anvende foedselsdag og beregnAlder() som ligger på Person, men også Hold, som ligger på Elev.
+
Bemærk at vi opretter e1 med fornavn og efternavn som egentlig hører til Person og hold som kun anvendes af Elev. Selv om det er en elev kan vi stadig anvende foedselsdag og beregnAlder() som ligger på Person, men også Hold, som kun ligger på Elev.
 +
 
 +
Rigtig mening giver det hvis vi bagefter laver klassen Laerer som også er en Person men ikke tilknyttet noget hold. Til gengæld får læreren løn som gemmes i attributten loen.
 +
    class Laerer:Person
 +
    {
 +
        private double loen;
 +
        public double Loen
 +
        {
 +
            get { return loen; }
 +
            set { loen = value; }
 +
        }
 +
 
 +
        public Laerer(string fornavn, string efternavn, double loen):base(fornavn,efternavn)
 +
        {
 +
            this.loen = loen;
 +
        }
 +
    }
 +
 
 +
Nu kan vil oprette både Laerer og Elev som begge arver fra Person og på den måde genbruge det fælles kode som ligger i Person.

Revision as of 14:32, 15 April 2015

Simple class

Objekt orienteret programmering er en måde at samle sine data på, et objekt kunne f.eks. være en person eller en bil. Disse objekter beskrives i klasser.


Attributes

Attributter er de variable som fortæller noget om klassens objekter. Vi kunne forestille os klassen Person skulle indeholde oplysninger om Navn og Alder.

I CSharp ville klassen se sådan ud.

   class Person
   {
       public string navn;
       public int alder;
   }

Klassen Person indeholder altså variablen navn af type string og alder af typen int. Disse variable kaldes for klassens attributter.

Når vi skal anvende klassen Person foregår det på følgende måde

   Person bruger1;
   bruger1 = new Person();
   bruger1.navn = "Ole";
   bruger1.alder = 20;

Vi fortæller her at bruger1 er af typen Person, vi erklærer variablen bruger1. Efterfølgende initialisere vi bruger1 son en ny Person. Til sidst giver vi bruger1 navnet Ole og alderen 20.

Vi har nu samlet alle oplysninger om Ole i Objektet bruger1 af typen Person (Klasse). Objektet har Attributterne navn og alder. Vi siger at bruger1 er en instans af klassen Person og at klassen er blevet instantieret.

Fordelen er at vi nu kan oprette mange forskellige Personer som alle har hvert sit navn og alder.

På samme måde kunne vi definere klassen bil. Klassen har attributterne fabrikat og ejer.

   class Bil
   {
       public string fabrikat;
       public Person ejer;
   }

Bemærk at fabrikat er af typen string mens ejer er af typen Person. Vi anvender altså Person som en type på lige fod med string, int og alle andre variabel typer.

Vi kan nu bruge de to klasser på følgende måde

   Person bruger1 = new Person();
   bruger1.navn = "Ole";
   bruger1.alder = 20;

   Bil farsBil;
   farsBil = new Bil();
   farsBil.fabrikat = "Volvo";
   farsBil.ejer = bruger1;

Bemærk hvordan Personen bruger1 indsættes som ejer i farsBil.

Hvis vi efterfølgende vil udskrive navnet på den Person som ejer farsBil kan vi skrive

   Console.WriteLine(farsBil.ejer.navn);

Bemærk hvordan vi med punktum arbejder os ned igennem klasserne, startende med farsBil af typen Bil. På farsBil vælger vi attributten ejer der er af typen Person. På ejer vælger vi attributten navn der er af typen string.


Methods

Mens attributter er statiske oplysninger om objektet kan man også lave metoder (funktioner) som udfører noget. I eksemplet Person havde vi attributten alder, men det er jo noget der hele tiden ændre sig. I stedet kan vi lave attributten foedselsdag og lave metoden beregnAlder som returnere den aktuelle alder ud fra datoen her og nu.

   class Person
   {
       public string navn;
       public DateTime foedselsdag;

       public int beregnAlder()
       {
           int alder;
           alder = DateTime.Now.Year - foedselsdag.Year;
           return alder;
       }
   }

Metoden beregn alder returnerer et resultat af typen int. Denne kan efterfølgende anvendes som vist

       Person bruger1 = new Person();
       bruger1.navn = "Ole";
       bruger1.foedselsdag = new DateTime(1995, 12, 24);
       Console.WriteLine(bruger1.beregnAlder());

Ole har nu fået foedselsdag juleaften 1995 og når vi vil udskrive hans alder, sker det ved at kalde metoden beregnAlder() på bruger1. Da det er en metode (funktion) vi kalder skal der sættes en parentes efter metodenavnet. Du kan læse mere om CSharp og metoder her CSharp Methods

Constructor

En constructor er en metode som kaldes når vi opretter en ny instans af klassen. Hvis man ikke laver en constructor laver CSharp en default constructor. Her har vi lavet en constructor på klassen Bil.

   class Bil
   {
       public string fabrikat;
       public Person ejer;

       public Bil(Person p)
       {
           ejer = p;
       }
   }

Consturctoren tager en input parameter p af typen Person og gemme i sin lokale ejer. Når vi skal anvende klassen foregår det således.

   Person bruger1 = new Person();
   bruger1.navn = "Ole";
   bruger1.foedselsdag = new DateTime(1995, 12, 24);
   Console.WriteLine(bruger1.beregnAlder());
 
   Bil farsBil;
   farsBil = new Bil(bruger1);

I constructoren for Bil gemmes den overførte parameter p i attributten ejer. Navnet p er dog ikke særlig godt da det ikke fortæller noget om hvad vi forventer af input. Faktisk var det bedre hvis parameteren også hed ejer, men hvordan kender vi så forskel på den overførte parameter og attributten. Det løser vi ved at anvendet ordet this. I eksemplet herunder henviser ejer til den parameter som blev overført (tidligere p) og this.ejer til den lokale attribut.

   class Bil
   {
       public string fabrikat;
       public Person ejer;

       public Bil(Person ejer)
       {
           this.ejer = ejer;
       }
   }

For brugeren af klassen gør det ingen forskel.

Hvis man ikke altid ønsker at angive ejer når man opretter en ny instans af klassen Bil kan man lave flere constructore med forskellige parametre på samme måde som i method overloading. Brugeren af klassen kan så frit vælge om man vil anvende den ene eller den anden constructor.

   class Bil
   {
       public string fabrikat;
       public Person ejer;

       public Bil(Person p)
       {
           ejer = p;
       }

       public Bil()
       {

       }
   }

   Person bruger1 = new Person();
   bruger1.navn = "Ole";
 
   Bil farsBil = new Bil(bruger1);
   Bil morsBil = new Bil(); 

I eksemplet her oprettes farsBil med bruger1 som ejer mens morsBil oprettes uden ejer. Det sker ved at kalde hver sin constructor.

Properties

Properties er en måde at styrer adgang til klassens attributter. I eksemplerne indtil nu har alle attributter været public. Et alternativ til dette er private som betyder at klassens attributter kun kan tilgås fra klassens metoder, men ikke udefra. For alligevel at kunne arbejde med attributterne kan man anvende properties.

   class Person
   {
       private string navn;
       public string Navn
       {
           get { return navn; }
           set { navn = value; }
       }

       ... koden er afkortet...
   }

   Person bruger1 = new Person();
   bruger1.Navn = "Ole";

Bemærk attributten navn(lille start bogstav) er private og propertien Navn(stort start bogstav) er public. Ved properties opretter vi personens navn som private men laver en tilhørender public property Navn. Med get og set kan vi styrer læse og skrive adgang. Det er ikke et krav at property skal hedde det samme som attributten, men det er god skik.

Fordelen ved properties er, ud over muligheden for at styrer adgang, at vi har mulighed for at omdirigere data. Forestil dig vi gerne vil udvide koden så navn splittes op i fornavn og efternavn, men gerne vil bevare muligheden for at læse navn.

   class Person
   {
       private string fornavn;
       private string efternavn;
       public string Navn
       {
           get { return fornavn + efternavn; }
       }

       ...koden er afkortet...
 
       public Person(string fornavn, string efternavn)
       {
           this.navn = fornavn;
           this.efternavn = efternavn;
       }
   }

Her overføres data til attributterne fornavn og efternavn i klassens constructor, derefter kan de ikke længere ændres da de begge er private. De to strenge sættes sammen til det fulde navn i propertien Navn som er public man kun har get (læse) adgang.

Inheritance

Inheritance giver mulighed for at lave en specialisering af vores klasser. Det kunne være vi gerne ville lave klassen Elev som har attributterne navn, foedselsdag og hold. Da Person allerede har navn og foedselsdag kan vi vælge af arve fra klassen Person og kun tilføje attributten hold.

   class Person
   {
       private string fornavn;
       private string efternavn;
       public string Navn
       {
           get { return fornavn + efternavn; }
       }
 
       public Person(string fornavn, string efternavn)
       {
           this.navn = fornavn;
           this.efternavn = efternavn;
       }
   }

   class Elev : Person
   {
       private string hold;
       public string Hold
       {
           get { return hold; }
           set { hold = value; }
       }

       public Elev(string fornavn, string efternavn, string hold):base(fornavn,efternavn)
       {
           this.hold = hold;
       }
   } 

Bemærk hvordan Elev arver fra klassen Person med Elev:Person. Bemærk også constructoren for Elev som sender parametrene fornavn og efternavn videre til :base (Person) og selv håndterer hold. Efterfølgende kan vi oprette en instans af Elev som følgende.

       Elev e1 = new Elev("Ole", "Olsen", "Hold1");
       e1.foedselsdag = new DateTime(1995, 12, 24);
       Console.WriteLine(e1.beregnAlder);
       Console.WriteLine(e1.Hold);

Bemærk at vi opretter e1 med fornavn og efternavn som egentlig hører til Person og hold som kun anvendes af Elev. Selv om det er en elev kan vi stadig anvende foedselsdag og beregnAlder() som ligger på Person, men også Hold, som kun ligger på Elev.

Rigtig mening giver det hvis vi bagefter laver klassen Laerer som også er en Person men ikke tilknyttet noget hold. Til gengæld får læreren løn som gemmes i attributten loen.

   class Laerer:Person
   {
       private double loen;
       public double Loen
       {
           get { return loen; }
           set { loen = value; }
       }
       public Laerer(string fornavn, string efternavn, double loen):base(fornavn,efternavn)
       {
           this.loen = loen;
       }
   }

Nu kan vil oprette både Laerer og Elev som begge arver fra Person og på den måde genbruge det fælles kode som ligger i Person.