C# out og ref-parametre

Har man brug for at få værdier ud af en funktion kan man naturligvis bruge funktionens returværdi, hvilket er oplagt i de fleste tilfælde. Der kan dog være tilfælde, hvor man har brug for at returnere flere værdier fra en funktion og i disse tilfælde har man et par yderligere muligheder.

out-parametre

Med out-parameteren kan man sende en værdi ud af et funktionskald. Parameteren SKAL tildeles en værdi inde i funktionen, ellers får man en compilefejl. Parameteren er KUN til output, evt. værdi i input vil blive ignoreret. Følgende vil give en compilefejl (fordi p endnu ikke er tildelt en værdi inde i fn, inden den refereres):

void fn(out int p)
{
    return p + 1;
}
var x = 1;
fn(out x);

Samtidig opfattes denne parameter alene som en output-parameter, dvs. den værdi parameteren evt. måtte have i kaldet, kan ikke bruges i funktionen. Følgende vil f.eks. give en kørselsfejl, fordi parameteren p ikke er tildelt en værdi inden den bruges (inde i funktionen):

void fn(out int p)
{
    Console.WriteLine(p);
    p = 2;
}
var x = 10;
fn(out x);

ref-parametre

Med ref-parametre kan man sende værdier ind i en funktion og samtidig give funktionen mulighed for at ændre værdien af den parametere (så den også ændres i den kaldende parts variabel). Dette kunne se således ud:

void fn(ref int p)
{
    p++;
}
var x = 1;
fn(ref x);
// x er nu 2;

Denne måde at bruge ref på, kan være "farlig" og betragtes af mange som dårlig kodestil. Begrundelsen er, at kaldet til fn har en skjult sideeffekt på den kaldende parts kode. Denne sideeffekt er svær at forudse, hvis man ikke lige har adgang til koden i fn og kan se hvad der sker. Selvom man havde adgang til koden, var det ikke nødvendigvis let at gennemskue denne sideeffekt alligevel. Det er derfor ikke tilrådeligt, at benytte ref på denne måde.

Når ref-modifikatoren bruges er det den variabel som står på parameterens plads i kaldet, der ændres (direkte i den hukommelsesplads variablen ligger). Det betyder også, at når der medsendes en referencevariabel (bla. objekter, strenge, arrays), så er det referencen der ændres, dvs. der peges på en anden forkomst af den medsendte type. Dette er fordi referencevariable i sig selv er referencer (navnet havde nok allerede afsløret dette) og det er altså pegepinden der ændres.

Det samme gælder for simple typer, hvor værdien ændres direkte i den hukommelsesposition, hvor variablen er defineret inden kaldet til funktionen.

Hukommelsespositionen kan dels være på "heapen", dels på stakken. Stakken benyttes hvis kaldet sker med en lokal variabel fra en anden funktion.

Comment