Introduktion till programmering med C# : Metoder
Innehållsförteckning
Del 3.
Metoder
Vi ska nu börja gå igenom metoder, hur vi skapar dem och hur vi anropar dem.
Metod Definition
En metod består av två delar
- En specifikation(även kallat header eller interface). Som beskriver hur vi kan använda metoden.
- En kropp(även kallat body eller implementering). Som beskriver vad metoden utför.

Definitionen på en metods specifikation är som följer:
[Qualifiers] [Return Type] Name ([Parameters/Arguments])
I vårt fall ovan:
- Metodens namn är SayHello
- Qualifier eller Accessor är static
- static betyder att metoden är åtkomlig på klassnivå, utan att behöva skapa en objekt instans
- Vi har en parameter/argument som är av typen sträng(string)
- Return Type är i vårt fall en sträng, vilket betyder att vi kommer att returnera ett värde av typen sträng.
Metod Signaturer och överlagring
En metods signatur är metodens namn kombinerat med dess parametrar/argument
Så för att identifiera en metod som anropas så tittar exekverings motorn på signaturen, INTE enbart namnet.
Olika signaturer men med samma metodnamn innebär att det är olika metoder!
Låt oss ta ett exempel:
int Calc(int x){ return x; }
int Calc(double x){ return x; }
Om vi nu anropar metoden på följande sätt: Calc(2.25)
Vilken av metoderna kommer att anropas?
Svaret: den som tar en datatyp av typen double som argument/parameter, vi skickar in ett decimal tal och då väljs den metod som kan ta emot ett flyttal.
Detta kallas för överlagring(overloading), något som vi kommer att gå in på i detalj i modulen Objekt Orienterad Programmering med C#.
Överlagring Gone Wild
Det är väldigt lätt att hamna i ett läge där vi har väldigt många överlagringar av en och samma metod.
Låt oss säga att vi ska skapa en kalkylator som har en metod Sum som behöver ta olika antal heltals parametrar.
int Sum(int number1, int number2){}
int Sum(int number1, int number2, int number3){}
int Sum(int number1, int number2, int number3, int number4){}
int Sum(int number1, int number2, int number3, int number4, int number5){}
int Sum(int number1, int number2, ...){}
int Sum(int number1, int number2, ...){}
Detta är inte snyggt!
Framförallt är det inte ett korrekt sätt att lösa probemet på.
Hur ska vi göra istället?
Dynamiska parametrar
Om vi har ett okänt antal parametrar som vi måste kunna hantera i våra metoder så har vi några olika sätt att lösa detta på. Vi ska se på två olika alternativ här.
Alternativ 1.
Vi kan använda en array enligt följande exempel
//Vi skapar en metod som tar en array av heltal som parameter...
int Sum(int[] numbers{}
//Vi kan sedan anropa metoden med en array som parameter...
var result = Sum(new int[]{1,2,34, 75,12,43});
Ovanstående kod fungerar visserligen, men är inte så snygg ur ett användarvänligt perspektiv. Finns det något bättre sätt då? Givetvis, genom att använda params nyckelordet som finns i C# språket.
Nyckelordet params definierar att parametern tar ett variabelt antal parametrar.
//Vi skapar en metod som tar en array av heltal som parameter
//genom att använda nyckelordet params innan typen av array...
int Sum(params int[] numbers{}
//Vi kan sedan anropa metoden med variabelt antal heltal...
var result = Sum(1,2,34, 75,12,43);
Mer om parameter definitioner
De två sista sakerna om parametrar som jag kommer att ta upp är något som en del utvecklare anser vara "code smell" eller dålig kod. Oavsett så kommer ni att stöta på dem framför allt i kod som ni utnyttjar ifrån .NET ramverket och det är nyckelorden ref och out.
Ref nyckelordet
ref nyckelordet används för att definiera att en värde typ variabel som skickas till en metod ska behandlas som en referens typ.
ref används i huvudsak i tre olika sammanhang
- I en metods signatur och i anropet för att skicka med parametern som en referens.
- I en metods signatur för att returnera ett värde som en referens.
- I en metods implementering för att indikera att ett retur värde av referenstyp är lagrad lokalt för att låta den anropande koden ändra dess värde.
För att använda en ref parameter så måste både metodens signatur och anropet explicit använda nyckelordet ref.
Observera att ref används i metoder där parametrar är av värde typ men behöver behandlas som referens typer.
Låt oss se på ett exempel.
int x = 10;
int DoStuff(int y, ref int i)
{
i = 100;
return y * 2;
}
var result = DoStuff(2, ref x);
Console.WriteLine("Result from return statement {0}", result);
Console.WriteLine("Result from methods ref parameter {0}", x);
Ett par saker att observera här:
metoden DoStuff's andra parameter ska skickas in som en referens, fastän det är en heltals parameter.
I metoden sätter vi parametern i till värdet 100!
När vi anropar metoden så observera att vi anger nyckelordet ref framför variabeln x. Detta betyder att vi skickar inte värdet på x utan adressen till x.
Om vi nu kör exemplet så bör vi få följande output:
Result from return statement 4
Result from methods ref parameter 100
Out nyckelordet
Nyckelordet out kan hjälpa oss komma över ett problem med att metoder enbart kan definiera ett returvärde.
Givetvis kan vi definiera en array som returvärde på en metod. Detta är en väldigt vanligt metod när vi får tillbaka listor av information ifrån en metod. Om vi bara behöver få tillbaka några få extra värden så är det lite "overkill" att skapa en array.
Vad vi behöver göra för att uppnå målet att kunna returnera flera värden ifrån en metod är att använda nyckelordet out framför alla parametrar som ska gå att läsa tillbaka.
Vad som händer när vi anger nyckelordet out är att oavsett datatyp så kommer parametern att hanteras som om den vore en referenstyp.
Låt oss se på ett exempel.
int x;
int DoStuff(int y, out int i)
{
i = 100;
return y * 2;
}
var result = DoStuff(2, out x);
Console.WriteLine("Result from return statement {0}", result);
Console.WriteLine("Result from methods out parameter {0}", x);
Ett par saker att observera här:
Vi initierar inte vår lokala variabel x, vi kommer att få ett värde på x ifrån metoden.
metoden DoStuff's andra parameter ska skickas in som en referens, fastän det är en heltals parameter. Vi gör detta genom att definiera parameter som out.
I metoden sätter vi parametern i till värdet 100!
När vi anropar metoden så observera att vi anger nyckelordet out framför variabeln x. Detta betyder att vi skickar inte värdet på x utan adressen till x.
Om vi nu kör exemplet så bör vi få följande output:
Result from return statement 4
Result from methods out parameter 100
Summering ref och out
Vad är egentligen skillnaden på ref och out? De åstadkommer i princip samma sak, det vill säga tillåter en metod att hantera en värde typ som en referens typ.
Det kan vara svår att se skillnaden, men
- För att skicka med en variabel som ref, MÅSTE variabeln vara initierad, det vill säga att variabeln måste ha ett värde innan vi skickar med den till metoden
- För att skicka med en variabel som out behöver inte variabeln vara initierad. Detta görs av metodens implementering
Valfria parametrar
När vi definierar metoder kan vi bestämma vilka parametrar ska vara obligatoriska eller valfria. Alla anrop måste skicka med alla parametrar som är obligatoriska men kan ignorera de som är valfria.
För att definiera en metod med valfria parametrar så måste varje parameter ges ett standard värde. Om ett värde inte skickas med så kommer det angivna standardvärdet att användas.
Ett standard värde måste vara något av följande:
- Ett konstant uttryck
- En värdetyp
Låt oss se på ett exempel
int DoStuff(int x, int y = 20)
{
return x + y;
}
var result = DoStuff(2);
Console.WriteLine("Result from return statement {0}", result);
Observera att den 2:e parametern i DoStuff har ett standarvärde(20).
I anropet så ignoreras den parametern och standardvärdet används.
Resultatet blir då:
Result from return statement 22
Om vi istället skickar med ett värde.
var result = DoStuff(2, 10);
Console.WriteLine("Result from return statement {0}", result);
Resultatet blir då:
Result from return statement 12
Namngivna parametrar
Det sätt som vi hittills har skickat med parametrar till metoder på, är baserat på dess position i argumentlistan. Det är fullt möjligt att använda sig av namnen på parametrarna för att själv bestämma ordningen som man vill skicka in dem på.
Låt oss se ett exempel
void DoStuff(string name, double value, int mileage)
{
Console.WriteLine("name: {0}, value: {1}, mileage: {2}",
name, value, mileage);
}
DoStuff(mileage: 87500, value: 88000, name: "Renault Trafic");
Regler
Följande regler gäller för namngivna parametrar
- Om vi börjar ange parametrar namngivet får vi inte avsluta med positionsangivna parametrar
- Såvida de namngivna och positionsangivna parametrarna är på sina ursprunliga positioner
- Vi kan ange parametrar med sina position och sedan använda de namngivna i vilken ordning vi vill
Exempel
void DoStuff(string name, double value, int mileage)
// Detta är ok
DoStuff("Renault Trafic", mileage: 97500, value: 87000);
// Detta är också ok
DoStuff(name: "Renault Trafic", 87000, 97500);
// Detta är inte ok
DoStuff(name: "Renault Trafic", 87000, value: 97500);
//Ger oss följande felmeddelande
error CS1744: Named argument 'value' specifies a parameter for which a positional argument has already been given