Przekazywanie parametrów funkcji

0

Witam.
Mam taki oto kod:

public struct Forecast
    {
        public int Temperature { get; set; }
        public int Pressure { get; set; }
    }

    class Program
    {
        public static void ChangeTheString(string weather) { weather = "sunny"; }
        public static void ChangeTheArray(string[] rainyDays) { rainyDays[1] = "Sunday"; }
        public static void ChangeTheStructure(Forecast forecast) { forecast.Temperature = 35; }
        static void Main(string[] args)
        {

            string weather = "rainy";
            ChangeTheString(weather);
            Console.WriteLine("The weather is " + weather);

            string[] rainyDays = new[] {"Monday", "Friday" };
            ChangeTheArray(rainyDays);
            Console.WriteLine("The rainy days were on " + rainyDays[0] + " and "+rainyDays[1]);

            Forecast forecast = new Forecast {Pressure = 700, Temperature = 20 };
            ChangeTheStructure(forecast);
            Console.WriteLine("The temperature is " +forecast.Temperature + "C");
            Console.ReadKey();
        }
    }

Drugi output to : "The rainy days were on Monday and Sunday". Dlaczego wartość w rainyDays[1] została zmieniona? Czy to nie powinno działać na takiej samej zasadzie co pierwszy output, czyli zmienia tak naprawdę wartość zmiennej lokalnej? Dlaczego nie musimy tu użyć dyrektywy ref, aby odnieść się do konkretnej zmiennej? Trzeci output działa na tej samej zasadzie co pierwszy.

1

Tablice w C# są typami referencyjnymi.

1

W C# typy mogą być albo: wartościowe (value types), albo referencyjne (reference types). Typ wartościowy oznacza, że zmienna przechowuje wartość w przydzielonej jej, własnej pamięci. Typ referencyjny oznacza, że zmienna przechowuje tylko adres pamięci do wartości. Tu dokładniejsze objaśnienie: https://msdn.microsoft.com/en-us/library/t63sy5hs.aspx.

Value types to na przykład int. Tablica oraz string są typami referencyjnymi.

I teraz: trzeci output działa, jak natura chciała, czyli zmieniana jest tylko zmienna lokalna (przy okazji: struktura także jest typem wartościowym, ale tu struktury jako takiej nie zmieniasz).

Drugi output działa tak, że tablica rainyDays jest przekazywana przez referencję - co oznacza, że zmieniasz pierwotną tablicę, a nie sam parametr.

Właściwie najdziwniejsze, powiedziałbym, zachowanie jest przy pierwszym outpucie, ze stringiem (dla mnie również). String jest typem referencyjnym. Ale tu pierwotna zmienna weather nie ma zmienionej wartości. Czemu? Jak ja to rozumiem: referencję do zmiennej, tak samo jak samą zmienną, można przekazać zarówno przez referencję, jak i przez wartość! (obszerniej o tym możesz poczytać tutaj: http://stackoverflow.com/questions/1096449/c-sharp-string-reference-type oraz tutaj: **http://jonskeet.uk/csharp/parameters.html**; szczególnie sekcja "Sidenote" w drugim linku; moje wyjaśnienie to tylko słabe streszczenie tych linków).

Dziwne? Nie, ponieważ string jest typem immutable (niezmiennym). Dzięki temu jego zachowanie jest inne, niż typów referencyjnych, które można zmienić. Klasę mógłbyś zmienić. Ale stringu nie zmienisz, tak więc string musi zachować się w ten sposób, że przekazujesz nie obiekt typu wartościowego przez referencję (np. obiekt klasy), ale obiekt typu referencyjnego przez wartość (której nie możesz w przypadku stringu zmienić). Dlatego też, choć zmienna o typie string przechowuje referencję do wartości przez siebie reprezentowanej, to sam obiekt o typie string przekazywany jest przez wartość i z uwagi na to nie możesz zmienić go samego, ale zmieniasz jedynie zmienną lokalną.

(A dzięki słowu ref możesz napisać ref string w argumencie i wtedy będzie to przekazanie referencji przez referencję. Natomiast w twoim przykładzie przekazujesz referencję przez wartość.)

Patrz też: http://stackoverflow.com/questions/10325323/passing-arrays-by-value-and-by-reference.

(Mam nadzieję, że nie zamotałem. Nie za obszernie napisałem? :( Ale, hm, sam się wyedukowałem przy pisaniu tego postu.)

1 użytkowników online, w tym zalogowanych: 0, gości: 1