Metoder
Typer av metoder Man kan urskilja följande metodtyper Metoden Main en specialmetod som utgör entré till programmet. Konstruktor(er) som anropas när ett objekt skapas (instansieras). Destruktor som anropas när ett objekt dör, Metoden anropas automatiskt; man skall inte anropa den i koden. Man ska i stället använda metoden Dispose om man vill att Garbage Collector snabbare skall ta livet av något objekt.
Typer av metoder forts. Properties (get och set metoder) som möjliggör åtkomst till inkapslade (privata eller skyddade) variabler eller annan data i en klass. Standard (vanliga) metoder som utför en eller flera instruktioner. Det finns flera andra typer, t ex händelsehanterare (eventhandlers ) osv.
Metoddeklaration En metod består huvudsakligen av två delar: en metoddefination (methodheader, method signature) , en metodkropp modifierare returtyp MetodNamn(parametrar) private bool CheckValue(double belopp) { /*...kroppen ...*/ } public double Interpolera (( /*... parametrar*/ ) ) { /*... kroppen... */ } En metods Modifierare omfattar bl.a. synlighet. Default synlighet är private Man ska sträva efter att deklarera metoder som private, dock behöver vissa metoder (liksom properties) vara publika (public) för att kunna användas utifrån.
Metoden Main Att skriva ett C# program innebär att man skriver minst en klass. Denna klass måste implementera metoden Main OS kommer då att leta efter denna metod för att starta programmet. Man kan ha Main i flera klasser men man måste välja en av dem som entré till programmet. Detta görs i projektegenskaper i Visual Studio. Att kunna ha flera Main metoder i applikationen ger programmerarna möjlighet att test varje klass för sig. Om man kör Visual Studio fixas en Main metod automatiskt.
Metoden Main – fyra sätt public class TestProg { static void Main ( ) //... } static void Main (string[] args) static int Main() return 0; static int Main (string[] args) } //klass
Metoder med eller utan returvärde En metod utför sin uppgift och returnerar ett värde av en viss typ eller inget. En void-funktion är en metod utan returvärde En funktion med annan returtyp måste returnera ett värde av returtypen. Dessa två typer har olika syntax:
Returvärdet En funktion returnerar ett värde. Typen av detta värde måste deklareras i funktionens huvud. public string FormatValutaString(int kr) Returvärde är något specifikt värde man vill ha tillbaka från en funktioner. Värde = FunktionensNamn() Returvärdet sker med det nyckelordet return. Behöver man ha flera värden tillbaka så är det out-parameter som gäller Pubic string FunktionensNamn(int kr, out int res1, out double res2)
Returvärde forts. Return avbryter samtidigt exekvering av metoden. Satser som ev. finns efter en return-sats kommer inte att exekveras. Man kan ha flera return satser i en metod, t ex med if-else, eller switch satser. Syntax: return uttryck En void har inget returvärde fast man kan använd satsen return; för att t ex avbryta exekvering av en void funktion.
Metodanrop En metod behöver ”anropas” för att den ska utföra sitt jobb. För att kunna använda tjänster som en klass erbjuder behöver man anropa dess metoder. Anrop av en metod kan naturligtvis endast ske inifrån en annan metod som kan finnas i samma eller annan klass under förutsättning att metoden är nåbar beroende på åtkomligheten. Det är viktigt att den anropande metoden har access till den metod den vill använda. Åtkomligheten av en metod bestäms av någon modifierarna public, private, protected, internal och protected internal. public String FormatValutaString(decimal kr){ }
Metodkörning och lokala variabler Varje gång en metod anropas så initieras metodens lokala variabler på nytt och satser utförs igen. C# kompilatorn initierar inte automatiskt lokala variabler utan kräver initiering av programmeraren. Metodparametrar, dess lokala variabler samt returvärde av en funktion läggs på stackminnet. Dessa värden försvinner från minnet när metoden kört klart. Använd många lokala variabler för att spara mellanvärden och undvika långa, krångliga satser.
Anrop av void-metoder En metod anropas som en sats för sig själv: slump.SlumpaPositivtTal( 0, 9 ); Eftersom en metod inte returnerar ett värde, deklareras den som void.
Anrop av metoder med returvärde En icke void-funktion däremot anropas som en operarand i ett uttryck. Funktioner kan användas i uttryck på samma sätt som variabler. slumpTal = slump.SlumpaTal ( 0, 9 ) + 1; Console.WriteLine("slump tal {0}.", slump.SlumpaTal(0,9) ); string str = slump.SlumpaTal(0,9).ToString();
Vad händer? slumpTal = slump.SlumpaTal ( 0, 9 ) + 1; int SlumpTal (int start, int slut) { int tal = 0; //... return tal; } slumpTal = slump.SlumpaTal ( 0, 9 ) + 1; slumptal = tal+1
statiska metoder Statiska metoder är associerade med klasser med statiska fält, medan icke-statiska metoder är associerade med objekt (instanser) av sina klasser. Att notera: Statiska metoder kan endast nå statiska fält och konstanter (const). Icke-statiska metoder kan nå bägge!
Metodparametrar (argument) Metoder exekveras när de anropas. När en metod (metodA) använder sig av en annan (metodB), säger man att metodA anropar metodB. Parametrar är värden som överförs från den anropande (metodA) till den anropade metoden (metodB). Parametrarna kallas för aktuella parametrar i metodA (variabler eller konstanta värden i anropet) och formella parametrar (argument) i metodB.
Aktuella och formella parametrar Aktuella parameter kan vara konstanta värden men måste vara av rätt typ, dvs. av samma typ som formella parametrar. Aktuella parametrar måste anges i rätt ordning, dvs. i den ordning de motsvarande formella parametrarna är deklarerade. Det är alltså viktigt att antal, typ och ordning av aktuella parametrar matchar väl med formella parametrar. Aktuella och formella parametrar behöver inte heta likadana men även om de gör det, kan de två olika variabler .
Typ av parametrar Två olika sätt att skicka argument till metoden Referens Värde Metoden får en kopia av det värdet som skickas Original värdet ändras inte Man skickar adressen till var i minnet värdet är lagrad Original data ändras Snabbare för att data kopieras inte
Värde-parameter class Program { static void Main(string[] args) Program prog = new Program(); prog.Run(); } public void Run() int parameter1 = 12; int parameter2 = 25; Change(parameter1, parameter2); Console.WriteLine("Parameter1: {0}\nParameter2: {1}",parameter1, parameter2); public void Change(int parameter1, int parameter2) parameter1 += 10; parameter2 += 20; Parameter1: 12 Parameter2: 25
Ref-parameter ref: Argument skickas som referens Original värde kan ändras Variabeln är redan initierad (kompilator säger ifrån om inte) ref måste explicit anges i både aktuella som formella parameterlista
ref class Program { static void Main(string[] args) Program prog = new Program(); prog.Run(); } public void Run() int parameter1 = 12; int parameter2 = 25; Change(parameter1, parameter2); Console.WriteLine("Parameter1: {0}\nParameter2: {1}",parameter1, parameter2); public void Change(int parameter1, int parameter2) parameter1 += 10; parameter2 += 20; Parameter1: 22 Parameter2: 45
out-parameter out: Argument skickas som referens Original värde kan ändras Variabeln kommer att initieras i metoden out måste explicit anges i både aktuella som formella parameterlista
out class Program { static void Main(string[] args) Program prog = new Program(); prog.Run(); } public void Run() int parameter1 = 12; int parameter2; Change(parameter1, out parameter2); Console.WriteLine("Parameter1: {0}\nParameter2: {1}",parameter1, parameter2); public void Change(int parameter1, out int parameter2) parameter2 = 13; parameter1 += 10; parameter2 += 20; Parameter1: 12 Parameter2: 33
Variabelt antal parametrar Som sista parameter kan metod ha ett variabelt antal parametrar. Man får nämligen deklarera en array som sista parameter. Man kan sedan skicka olika antal värden. Nyckelordet params möjliggör detta. Det går att deklarera endast en params i varje parameterlista
params class Program { static void Main(string[] args) Program prog = new Program(); prog.Run(); } public void Run() int parameter2; Change(out parameter2, 12,13,26); Console.WriteLine("Parameter2: {0}",parameter2); public void Change(out int parameter2, params int[] numbers) parameter2 = 0; foreach (int i in numbers) parameter2 += i; Parameter2: 51
Metodöverlagring Metodöverlagring innebär att man får ha flera metoder i en klass med samma namn men med olika formella parametrar, enligt följande: olika antal parametrar olika parametertyp olika parameteröverförings sätt (värde, ref, out). När en metod anropas, väljer kompilatorn den metod som bäst matchar de aktuella parametrarna. vad gäller överlagring enbart med avseende på ref eller out finns en liten fallgrop. CLS innehåller ju regler som gör att komponenter skrivna i olika språk kan exekveras tillsammans, och en av de reglerna är att överlagring inte får ske enbart med avseende på parametrars modifierare. void SomeMethod ( int i ){ ... } void SomeMethod ( ref int i ){ ... } void SomeMethod ( int i, long j ){ ... } void SomeMethod ( long i, int j ){ ... } void SomeMethod ( char i) { ... }
Två metoder med bara olika returvärde funkar inte Att skriva metoder som endast skiljer på returtypen är inte tillåtet. int AnnanMetod () { ... } //Ej tillåtet string AnnanMetod () { ... } //Ej tillåtet Metoderna kan (felaktigt) anropas som en void metod: AnnanMetod (); // returvärdet ignoreras
Många systemmetoder är överlagrade I .NET ramverk är många metoder överlagrade. Det är tack vare överlagring som vi kan anropa t ex Console.WriteLine på olika sätt: Console.WriteLine(i) Console.WriteLine("Hej") Console.WriteLine("tal1: " & i & " tal2: " & sum) Ett annat exempel de olika former av metod Main som diskuterades i början av denna presentation.
Konstruktorn En konstruktor är en specialmetod som automatiskt exekveras vid skapande av ett objekt. Den används för att skapa objekt med initialvärden. Man ger klassens attribut (instansvariablerna) startvärde och/eller utföra initieringsfunktioner. När konstruktor saknas i en klass, skapar C# kompilatorn en defaultkonstruktor.
Används vid skapande av klass En konstruktor skapar objekt av sin klass den returnerar en referens till en instans av sin klass. En konstruktor initierar ett objekts tillstånd. När man skapar en instans av en klass med new anropas konstruktorn automatiskt. Har man flera konstruktorer i samma klass, väljer kompilatorn den som bäst matchar new -satsen. All kod som skrivs i konstruktorn anropas då automatiskt.
Deklaration av konstruktor Syntax: [attributes] [modifiers] identifier([formal-parameter-list]) [initializer] { constructor-body } En konstruktor är en metod som har samma namn som klassen har ingen deklarerad returtyp, inte ens void. Klass utan konstruktor får en default konstruktor utan parametrar av kompilatorn för att initiera objektets värde till defaultvärden, t.ex. int till 0, string-variabler till null, osv.
Ingen returtyp (public är modifier- are Exempel - konstruktor Samma namn Ingen returtyp (public är modifier- are
Exempel - forts
Skapa objekt av BankLoan En observationsbild från kodskrivning i VS.NET!
synlighet och överlagring Konstruktorer brukar vara deklarerade publikt (public) för att kunna synas när man skapar en instans av klassen utifrån. En private konstruktor kan inte nås utanför en klass och därför har man sällan en konstruktor som är privat. Konstruktorn kan överlagras, dvs. det kan finnas flera konstruktorer i samma klass. Överlagring innebär att man kan ha flera metoder i en klass med samma namn men med antingen olika typer av parametrar och/eller olika antal parametrar (se det föregående exemplet). Kompilatorn väljer då den metod (konstruktor i detta sammanhang) som bäst matchar anropet.
En konstruktor kan anropa en annan konstruktor i sin klass med nyckelordet this. En subklass (härledd klass) konstruktor kan anropa sin basklass konstruktor med nyckelordet base.
Destruktor - syntax Destruktorn är en motsvarighet till konstruktorn. Metoden anropas också automatiskt (om den finns) innan objektet plockas av skräpsamlaren, GC (garbage collector), för avlivning. Destruktorn används för att städa objektet t ex stänga filer som objektet hållit öppna. Basklassens destruktor anropas också automatiskt om klassen är härledd. De flesta klasser behöver ingen destruktor.
Destruktor - syntax En destruktor samma namn som klassen deklareras med vågtecknet ~ är varken public, private, protected eller internal. har ingen returtyp. En defaultdestruktor (tom) skapas automatiskt av kompilatorn om sådan saknas.
Destruktor Normalt behöver man inte bry sig om destruktorer eftersom det är GCs jobb att ta hand om objekt som skall städas. Men man vet aldrig när och i vilken ordning GC plockar objekten. I vissa fall, i synnerhet när man skapar grafiska objekt vill man att lokala objekt avlivas så fort de inte används längre för att befria minnet. I dessa fall skall man anropa objektets Dispose metod.
Tips och råd Ett par råd: Anropa aldrig destruktorn. Ha ingenting att göra med GC. public class MyResource : IDisposable { public void MyResource() // Acquire valuble resource } public void Dispose() // Release valuble resource public void DoSomething() ...
Operatoröverlagring
Operatoröverlagring. Vad är det bra till? Det är inga nya funktionalitet som läggs till språket Det tillför inte ngn prestanda vinst Det gör inte lättare att programmera klasser Men Det kan hjälpa abstraktionen, om det används rätt t.ex. point3 = point1 + point2;
Operatoröverlagring + - ! ~ true false ++ -- + - * / ! ~ % & | ^ == != Överlagrade unära operatorer + - ! ~ true false ++ -- Överlagrade binära operatorer + - * / ! ~ % & | ^ == != << >> < > <= >=
Operatoröverlagring Dessa operatorer [ ] ( ) && || ?: går inte att överlagra. Operatorer som inte redan finns i C#-språket går inte att överlagra. Jämförelse operatorer (== och !=) kan överlagras. Hur som helst, om (==) överlagras så måste (!=) även överlagras. Dvs. man måste överlagra Equals och GetHashCode metoder. Tilldelningsoperatorn (=) kan inte överlagras. Men när man överlagra binära operatorer så blir de sammansatta operatorerna implicita överlagrade. T.ex. om man överlagra + operator, då blir += operator överlagrad per automatik. Mindre än (<)-operatorn och större än (>)-operatorn måste överlagras i par. I andra ord om man överlagra den ena måste då överlagra den andra.
Operatoröverlagring Måste vara statisk class Complex { private int real; private int imaginary; public static Complex operator ==(Complex c1, Complex c2) return new Complex(c1.real+c2.real,c1.imaginary+c2.imaginary); }
Tips! operatoröverlagring Det måste finnas logisk mening med att överlagra operatorer. Låt oss säga att du överlagrade *-operatorn för klassen Bil. Vad är meningen att multiplicera två bilobjekt? Inte mycket. Operatoröverlagringen är generellt användbart endast vid skapande av användbara typer. T.ex. Punkt, komplexa tal. Operatoröverlagring är inte definierad i CLS(Common Language System). Därför du bör undvika operatoröverlagring om du vill vara säkert att klassen du skapade ska användas i andra språk.
Indexers
Översikt Används för att möjliggöra access till en klass genom arraynotation, dvs. myClass[x]; En indexerare är likt en property, har två användardefinierade metoder för åtkomst av information. Innehåller en get och en set metod. get sökmetoden set addmetoden En indexerare har alltid namnet this och tar parametrar inom [ ] istället för ( ). Logiskt sett är det operatoröverlagring av [ ] det handlar om.
Indexer set get class Program { static void Main(string[] args) class Person { private string name; private string ssn; private List<string> dagbok = new List<string>(); public string Ssn get { return ssn; } } public string Name get { return name; } set { name = value; } public string this[int pos] get {return dagbok[pos];} set { dagbok.Add(value); } public Person(string name, string ssn) this.name = name; this.ssn = ssn; public override string ToString() return String.Format("{0} {1}", Name, Ssn); set class Program { static void Main(string[] args) Person p = new Person("kalle", "1234"); p[0] = "Måndag: god lunch"; p[1] = "Tisdag: tråkigt föreläsning(jag menar inte C#)"; Console.WriteLine("{0} har skrivit följande: \n{1}\n{2}”, p.ToString(), p[0].ToString(), p[1].ToString() ); } get