03. december 2008 - 23:33Der er
23 kommentarer og 2 løsninger
C#: Accessor og Mutator
Jeg er lidt usikker på, hvordan man smartest kan lave Accessor og Mutator metoder i C# (.NET 3.5).
Her kommer lige lidt kode:
interface Person { bool Name { get; set; } }
class Student : Person { bool Name { get; set; } }
Er det måden man skal bygge det op på? Og så sætte navnet sådan (mutator): student.Name = "Per";
Og så hente navnet sådan (accessor): label.Text = student.Name;
Er det den rigtige måde at gøre det på? Som det kører der, er Name en feltvaribel, men kan man lave det samme, hvor det er en metode? Så man f.eks. kan hente sådan student.Name();
Jeg kommer fra en Java-verden, så er meget vant til getName() og setName(). Men kan lidt fornemme, at det ikke er måde man gør det på i C#?
Håber der er nogen der kan hjælpe mig lidt her :) Alle kommentarere er velkomne!
Properties er en af de store forskelle fra java og C# og så er det ikke ret meget mere end et compiler trick. Tag udgangspunkt i denne kode
public class Kunde { string _navn; int _alder;
public Kunde() {
}
public string Navn { get { return _navn; } set { _navn = value; } }
public int Alder { get { return _alder; } set { _alder = value; } }
} Der er her en klasse, kunde, som indeholder et navn og en alder. I Java ville man typisk lave en set-metode og en get-metode for at kunne tilgå disse variabler udefra. I c# er der mulighed for at lave properties. Det giver reelt denne forskel, som du også selv beskriver: [i JAVA] //sætter alderen til kundens alder int alderen = kunde.getAlder(); //sætter kundens navn til søren kunde.setNavn("søren"); //inkrementerer kundens alder (det er hans fødselsdag) kunde.SetAlder(kunde.getAlder() + 1); [i C#] //sætter alderen til kundens alder int alderen = kunde.Alder; //sætter kundens navn til søren kunde.Navn = "søren"; //inkrementerer kundens alder (det er hans fødselsdag) kunde.Alder++;
Det er oftest nemmere at skrive properties end det er at lave get og set metoder og så kan man argumentere for at det giver kønnere kode (specielt i sidste eksempel hvor kundens alder inkrementeres). Men hov - formålet med at man laver get og set metoder er jo muligheden for at kontrollere variabler og f.eks forhindre at alderen sættes til -9. I java giver det sig selv at man så laver setmetoden således: public void setAlder(int nyAlder) { if(nyAlder >= 0) alder = nyalder else throw new InvalidAgeException(); }
Det kan man ikke med properties, eller hvad?
Det kan man godt, for man kan betragte det der står mellem tuborg efter set, som setmetodens kode. Lige nu sætter den bare _alder lig med hvad end der står i value (value er et reserveret ord og svarer til den værdi man forsøger at 'sætte' til, her er value f.eks 9: kunde.Alder = 9;), men skal der validering til kan det også gøres meget enkelt:
public int Alder { get { return _alder; } set { if (value >= 0) _alder = value; else throw new InvalidAgeException(); } }
hvis jeg nu skriver: kunde.Alder = -67; vil jeg få en exception kastet i hovedet.
Microsoft introducerede noget nyt i deres compiler - en nemmere måde at skrive properties på. I mange tilfælde har man brug for at lave en property uden validering, som det er tilfældet i det første kode. Derfor har man lavet en nemmere måde at gøre det på og jeg kunne i stedet for det første kode have skrevet
public class Kunde {
public Kunde() {
}
public string Navn { get; set; }
public int Alder { get; set; }
}
Det der sker her er at programmet opretter nogle variabler til mig, en string og et navn - hver gang en af disse properties anvendes, sættes eler gettes den variabel. Når du skal tilgå disse variabler inden i klassen, bruger du property navnet dvs. Navn = "lars"; Det er det samme du gør i dit eget eksempel og det er som sagt bare en nemmere måde at skrive disse properties på.
Du kan ikke skrive student.Name(), hvis Name er en property - men der er ingen som forhindrer dig i at lave en metode som hedder Name, hvorefter det vil være muligt. Det er bare den måde man normalt gør det i C#.
Jeg kommer selv fra en Java verden inden jeg prøvede kræfter med C# og jeg håber du kommer til at holde ligeså meget af properties, som jeg er kommet til.
Jeg har kun et enkelt spørgsmål tilbage: Er det den rigtige måde, hvorpå jeg i mit interface angiver at der skal implementeres en property - eller kan det gøres smartere? Det er jo faktisk den samme kode som der står i klasse som implementerer interfacet.
Skal også lige vænne mig til, at man skal bruge : for både implements og extends. Men synes egentligt ikke så godt om det, da man ikke umiddelbart kan se, om en klasse implementerer noget eller extender noget - så er man nødt til at skulle over og kigge i den klasse som der står. Er det ikke korrekt?
Der er dog en ting jeg ikke helt kan gennemskue. Lad os antage noget lignende dette:
class Kunde {
public Kunde() { this.IsPartner = false; }
public bool IsPartner { get; set; } }
Da jeg gerne vil have, at IsPartner er false, med mindre jeg har sat den til andet, har jeg smidt en accessor i konstruktøren. Men er der ikke en smartere måde man kan gøre det på? Hvis jeg f.eks. har en klasse med 5 konstruktører, er det lidt træls at skulle sætte den i alle 5. Jeg har prøvet med noget lignende dette:
Jeg kan vaere meget enig i extend implements - i praksis lader man i .NET altid interfaces navne starte med I, saaledes at man ved at IPerson er et interface og ikke en klasse.
Har du arbejdet med Test i Visual Studio 2008? Da jeg ikke har tid til at lave de test-cases som tester de kritiske punkter for en funktion i min kode, har jeg lavet én TestMethod som har en for-løkke som kører denne funktion 1000 gange. Jeg ved godt, at det ikke er ideen med test-cases at de skal indeholder løkker m.m. Jeg tænkte, om det er muligt at fortælle den, at den skal køre f.eks. 1000 gange? Det vil jo også være smart, at der stod 1000 test-cases under "Test Results" vindue i stedet for den ene som der står nu.
Ville da lige knytte en kommentar ang. abstrakte klasser - har aldrig hørt om en officiel navngivning af dem, men jeg synes at have lagt mærke til at de ofte fra Microsoft's side (I hvert fald I den nyere del af deres kode, som f.eks. MVC frameworket til ASP.Net) lader abstrakte klasser ende på "Base", altså f.eks. PersonBase - hvilket vel også giver meget god mening? Dog er det ikke noget der på nogen måde er lige så gennemført som stort I ved interfaces, jeg tror de fleste fra .Net verdenen ville kigge mærkeligt efter en hvis man ikke benyttede sig af den "regel".
I må undskylde at jeg spammer her, men sidder med et akut problem, som jeg meget gerne vil have en løsning på. Håber I kan hjælpe mig her: http://www.eksperten.dk/spm/856076
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.