MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Transmisia parametrilor prin valoare și prin referință - Parametri de ieșire

În C# există două moduri de a transmite parametrii într-o metodă: prin valoare și prin referință.

Transmisia parametrilor prin valoare

Cea mai simplă metodă de a transmite parametrii este prin valoare, adică metoda obișnuită de transmisie a parametrilor:

void Increment(int n)
{
   n++;
   Console.WriteLine($"Numărul în metoda Increment: {n}");
}

int number = 5;
Console.WriteLine($"Numărul înainte de metoda Increment: {number}");
Increment(number);
Console.WriteLine($"Numărul după metoda Increment: {number}");

Ieșirea pe consolă:

Numărul înainte de metoda Increment: 5
Numărul în metoda Increment: 6
Numărul după metoda Increment: 5

La transmisia argumentelor parametrilor prin valoare, parametrul metodei primește nu variabila propriu-zisă, ci copia acesteia și lucrează cu această copie independent de variabila originală.

Astfel, în exemplul de mai sus, la apelul metodei Increment, aceasta primește copia variabilei number și îi mărește valoarea acestei copii. De aceea, în metoda Increment vedem că valoarea parametrului n a crescut cu 1, dar după executarea metodei, variabila number are valoarea inițială - 5. Adică se modifică copia, iar variabila originală rămâne neschimbată.

Transmisia parametrilor prin referință și modificatorul ref

La transmisia parametrilor prin referință, în fața parametrilor se folosește modificatorul ref:

void Increment(ref int n)
{
   n++;
   Console.WriteLine($"Numărul în metoda Increment: {n}");
}

int number = 5;
Console.WriteLine($"Numărul înainte de metoda Increment: {number}");
Increment(ref number);
Console.WriteLine($"Numărul după metoda Increment: {number}");

Ieșirea pe consolă:

Numărul înainte de metoda Increment: 5
Numărul în metoda Increment: 6
Numărul după metoda Increment: 6

La transmisia valorilor parametrilor prin referință, metoda primește adresa variabilei în memorie. Astfel, dacă în metodă se modifică valoarea parametrului transmis prin referință, se modifică și valoarea variabilei transmise ca argument.

Astfel, în metoda Increment se transmite referința la variabila number din memorie. Dacă valoarea parametrului n din Increment se modifică, aceasta duce și la modificarea variabilei number, deoarece atât parametrul n, cât și variabila number indică aceeași adresă în memorie.

Observați că modificatorul ref este specificat atât înaintea parametrului la declarația metodei, cât și la apelul metodei, înaintea argumentului transmis parametrului.

Parametrii de ieșire - Modificatorul out

Anterior am folosit parametri de intrare. Dar parametrii pot fi și de ieșire. Pentru a face un parametru de ieșire, în fața acestuia se pune modificatorul out:

void Sum(int x, int y, out int result)
{
   result = x + y;
}

Aici rezultatul se returnează nu prin operatorul return, ci prin parametrul de ieșire result. Utilizarea în program:

void Sum(int x, int y, out int result)
{
   result = x + y;
}

int number;
Sum(10, 15, out number);
Console.WriteLine(number);   // 25

La fel ca și în cazul ref, cuvântul cheie out este folosit atât la definirea metodei, cât și la apelul metodei.

De asemenea, observați că metodele care folosesc astfel de parametri trebuie să le atribuie o valoare. De exemplu, următorul cod va fi invalid, deoarece pentru parametrul out nu este specificată nicio valoare:

void Sum(int x, int y, out int result)
{
   Console.WriteLine(x + y);
}

Avantajul utilizării acestor parametri este că putem returna din metodă nu doar o singură valoare, ci mai multe. De exemplu:

void GetRectangleData(int width, int height, out int rectArea, out int rectPerimeter)
{
   rectArea = width * height;       // aria dreptunghiului - produsul dintre lățime și înălțime
   rectPerimeter = (width + height) * 2; // perimetrul dreptunghiului - suma lungimilor tuturor laturilor
}

int area;
int perimeter;

GetRectangleData(10, 20, out area, out perimeter);

Console.WriteLine($"Aria dreptunghiului: {area}");       // 200
Console.WriteLine($"Perimetrul dreptunghiului: {perimeter}");   // 60

Aici avem o metodă GetRectangleData, care primește lățimea și înălțimea dreptunghiului (parametrii width și height). Folosim doi parametri de ieșire pentru a calcula aria și perimetrul dreptunghiului.

Putem, de asemenea, defini variabilele care sunt transmise parametrilor out direct la apelul metodei. Astfel, putem simplifica exemplul anterior:

void GetRectangleData(int width, int height, out int rectArea, out int rectPerimeter)
{
   rectArea = width * height;  
   rectPerimeter = (width + height) * 2;
}

GetRectangleData(10, 20, out int area, out int perimeter);

Console.WriteLine($"Aria dreptunghiului: {area}");       // 200
Console.WriteLine($"Perimetrul dreptunghiului: {perimeter}");   // 60

Dacă nu cunoaștem tipul valorilor care vor fi atribuite parametrilor, putem folosi operatorul var pentru a le defini:

GetRectangleData(10, 20, out var area, out var perimeter);

Console.WriteLine($"Aria dreptunghiului: {area}");       // 200
Console.WriteLine($"Perimetrul dreptunghiului: {perimeter}");   // 60

Parametrii de intrare - Modificatorul in

Pe lângă parametrii de ieșire cu modificatorul out, o metodă poate folosi și parametri de intrare cu modificatorul in. Modificatorul in indică faptul că acest parametru va fi transmis în metodă prin referință, însă în interiorul metodei valoarea parametrului nu poate fi modificată. De exemplu, să luăm următoarea metodă:

void GetRectangleData(in int width, in int height, out int rectArea, out int rectPerimeter)
{
   //width = 25; // nu se poate modifica, deoarece width este un parametru de intrare
   rectArea = width * height;      
   rectPerimeter = (width + height) * 2;
}

int w = 10;
int h = 20;
GetRectangleData(w, h, out var area, out var perimeter);

Console.WriteLine($"Aria dreptunghiului: {area}");       // 200
Console.WriteLine($"Perimetrul dreptunghiului: {perimeter}");   // 60

În acest caz, prin parametrii de intrare width și height sunt transmise valorile în metodă, dar în interiorul metodei nu putem modifica valorile acestor parametri, deoarece sunt definiți cu modificatorul in.

Transmisia prin referință poate crește performanța în anumite cazuri, iar utilizarea operatorului in garantează că valorile variabilelor transmise parametrilor nu pot fi modificate în această metodă.

Parametri ref doar pentru citire

În exemplele de mai sus, valorile parametrilor ref puteau fi modificate. Totuși, uneori acest lucru poate fi nedorit. Pentru a garanta că un parametru ref nu-și va schimba valoarea, începând cu versiunea C# 12, se pot folosi parametri ref doar pentru citire. Acești parametri sunt precedați de cuvântul cheie readonly:

void Increment(ref readonly int n)
{
   // n++; // nu se poate, altfel va fi o eroare de compilare
   Console.WriteLine($"Numărul în metoda Increment: {n}");
}
 
int number = 5;
Increment(ref number);
Console.WriteLine($"Numărul după metoda Increment: {number}");

În acest caz, în metoda Increment parametrul n este transmis prin referință și este disponibil doar pentru citire. Încercarea de a modifica valoarea sa va genera o eroare la compilare.

← Lecția anterioară Lecția următoare →