Cvičení – použití parametrů hodnotového a referenčního typu

Dokončeno

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

  1. V editoru Visual Studio Code odstraňte veškerý existující kód z předchozích cvičení.

  2. 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, ba c jsou 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 c bude?

  3. 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 = 0
    

    Všimněte si, že hodnota c je změněna pouze v rámci Multiply metody. Mimo metodu c zachová původní hodnotu.

Test předání odkazem

  1. Odstraňte předchozí kód z editoru Visual Studio Code.

  2. 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í PrintArray metody. Metoda Clear je 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?

  3. Uložte a spusťte kód, abyste mohli sledovat následující výstup:

    1 2 3 4 5 
    0 0 0 0 0
    

    Všimněte si, že pole zůstává mimo rozsah metody Clear změněno. K tomu dochází, protože Clear metoda 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.

  1. V editoru Visual Studio Code odstraňte veškerý existující kód z předchozích cvičení.

  2. 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}");
    }
    
  3. Uložte a spusťte kód, abyste mohli sledovat následující výstup:

    Start: Healthy
    Middle: Unhealthy
    End: Healthy
    

    SetHealth Pokud 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.

  4. 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í status proměnnou s novou řetězcovou hodnotou.

  5. Uložte a spusťte kód, abyste mohli sledovat následující výstup:

    Start: Healthy
    Middle: Unhealthy
    End: Unhealthy
    

    Aktualizovaný ř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.