Cvičení – použití parametrů hodnotového a referenčního typu
V jazyce C# lze proměnné zařadit do dvou hlavních typů, typů hodnot a referenčních typů. Tyto typy popisují, jak proměnné ukládají své hodnoty.
Typy hodnot, například int, , boolfloatdoublea char přímo obsahují hodnoty. Odkazové typy, jako jsou string, array a objekty (například instance Random), neukládají své hodnoty přímo. Odkazové typy místo toho ukládají adresu, do které se ukládají jejich hodnoty.
Parametry předané hodnotou a předané odkazem
Pokud je argument předán metodě, proměnné typu hodnoty mají jejich hodnoty zkopírovány do metody. Každá proměnná má vlastní kopii hodnoty, takže původní proměnná se nezmění.
S odkazovými typy se adresa hodnoty předá metodě. Proměnná zadaná metodě odkazuje na hodnotu na této adrese, takže operace s danou proměnnou ovlivňují hodnotu, na kterou odkazuje druhý.
Poznámka:
Je důležité si uvědomit, že string jde o odkazový typ, ale je neměnný. To znamená, že jakmile má přiřazenou hodnotu, nedá se změnit. Když se v jazyce C# použijí metody a operátory k úpravě řetězce, výsledek vrácený je ve skutečnosti nový objekt řetězce.
V tomto cvičení se dozvíte více o předávání argumentů typu reference a hodnoty do metod.
Test předávání hodnotou
V editoru Visual Studio Code odstraňte veškerý existující kód z předchozích cvičení.
Do editoru visual studio Code zadejte následující kód:
int a = 3; int b = 4; int c = 0; Multiply(a, b, c); Console.WriteLine($"global statement: {a} x {b} = {c}"); void Multiply(int a, int b, int c) { c = a * b; Console.WriteLine($"inside Multiply method: {a} x {b} = {c}"); }Proměnné
a,bacjsou předány metoděMultiply. Hodnoty proměnných se vytisknou během provádění metody a po dokončení metody se znovu vytisknou.Celá čísla jsou hodnotové typy, jejichž hodnoty se zkopírují při předání do metod. Co si myslíte, že výstup
cbude?Uložte a spusťte kód, abyste mohli sledovat následující výstup:
inside Multiply method: 3 x 4 = 12 global statement: 3 x 4 = 0Všimněte si, že hodnota
cje změněna pouze v rámciMultiplymetody. Mimo metoduczachová původní hodnotu.
Test předání odkazem
Odstraňte předchozí kód z editoru Visual Studio Code.
Do editoru visual studio Code zadejte následující kód:
int[] array = {1, 2, 3, 4, 5}; PrintArray(array); Clear(array); PrintArray(array); void PrintArray(int[] array) { foreach (int a in array) { Console.Write($"{a} "); } Console.WriteLine(); } void Clear(int[] array) { for (int i = 0; i < array.Length; i++) { array[i] = 0; } }Kód začíná inicializovaným
array, aby obsahoval některé celočíselné hodnoty. Hodnoty se zobrazí pomocíPrintArraymetody. MetodaClearje volána na pole, a poté je pole vytištěno znovu.Pole jsou odkazové typy. Odkazové typy ukládají adresu svých hodnot do paměti. Co si myslíte, že výstup bude?
Uložte a spusťte kód, abyste mohli sledovat následující výstup:
1 2 3 4 5 0 0 0 0 0Všimněte si, že pole zůstává mimo rozsah metody
Clearzměněno. K tomu dochází, protožeClearmetoda aktualizovala hodnoty uložené na každé adrese.
Testování s řetězci
Dříve jste se dozvěděli, že řetězce jsou neměnným typem. I když je řetězec referenčním typem, jeho hodnotu nelze po přiřazení změnit, na rozdíl od pole. Možná jste si toho všimli, pokud jste použili metody jako string.Replace nebo string.ToUpper. V této úloze se dozvíte, jak opravit běžnou chybu zjištěnou při práci s řetězci.
V editoru Visual Studio Code odstraňte veškerý existující kód z předchozích cvičení.
Do editoru visual studio Code zadejte následující kód:
string status = "Healthy"; Console.WriteLine($"Start: {status}"); SetHealth(status, false); Console.WriteLine($"End: {status}"); void SetHealth(string status, bool isHealthy) { status = (isHealthy ? "Healthy" : "Unhealthy"); Console.WriteLine($"Middle: {status}"); }Uložte a spusťte kód, abyste mohli sledovat následující výstup:
Start: Healthy Middle: Unhealthy End: HealthySetHealthPokud metoda nevypíše stav, pravděpodobně jste předpokládali, že se metoda nespustí správně. Místo toho byl vytvořen nový řetězec s hodnotou "Nezdravý" a poté ztracen v rámci rozsahu metody.Chcete-li tento problém vyřešit, můžete změnit
SetHealth, aby místo toho používal globální stavovou proměnnou.Aktualizujte kód následujícím způsobem:
string status = "Healthy"; Console.WriteLine($"Start: {status}"); SetHealth(false); Console.WriteLine($"End: {status}"); void SetHealth(bool isHealthy) { status = (isHealthy ? "Healthy" : "Unhealthy"); Console.WriteLine($"Middle: {status}"); }V tomto kódu přepíšete globální
statusproměnnou s novou řetězcovou hodnotou.Uložte a spusťte kód, abyste mohli sledovat následující výstup:
Start: Healthy Middle: Unhealthy End: UnhealthyAktualizovaný řetězec se teď zachytí a uloží správně.
Rekapitulace
Zde je to, co jste se dosud naučili o hodnotových a referenčních typech parametrů:
- Proměnné lze kategorizovat jako typy hodnot a odkazové typy.
- Typy hodnot přímo obsahují hodnoty a odkazové typy ukládají adresu hodnoty.
- Metody používající argumenty typu hodnoty vytvářejí vlastní kopii hodnot.
- Metody, které provádějí změny u parametru pole, ovlivňují původní vstupní pole.
- Řetězec je neměnný referenční typ.
- Metody, které provádějí změny u parametru řetězce, nemají vliv na původní řetězec.