Niespodzianka w przekazywaniu przez referencję

Co powiesz na poniższy kod? Co się stanie?

   1: static void Main(string[] args)
   2: {
   3:     StringBuilder sb = new StringBuilder();
   4:     Method(sb);
   5:     Console.WriteLine(sb.ToString());
   6: }
   7:  
   8: static void Method(StringBuilder fooSB)
   9: {
  10:     fooSB.Append("test");
  11:     fooSB = null;
  12: }

Muszę Ci powiedzieć, że źle zgadałem co się stanie. Pierwszą moją myślą, było, że podczas wykonania się programu w linijce 5 zostanie wyrzucony wyjątek NullReferenceException. A co się okazało po uruchomieniu programu w Visual Studio? Wyświetlił się napis “test”. Co jak już napisałem z początku mnie zaskoczyło.

No ale w czym tkwi szczegół. Przecież obiekty do metod są przekazywane przez referencje i w tym przypadku tak powinno się wykonać. Nawet dowodzi to, że do StringBuildera został dodany napis “test”. Szczegół w tym, że sama referencja jest przekazywana przez wartość. Co oznacza, że do metody jest kopiowany adres, pod którym znajduje się StringBuilder i wszystkie operacje na nim są ok.

Natomiast jeśli zmienimy samą referencje – przypiszemy jej wartość null, to zmienia się wartość kopi oryginalnej referencji, a nie oryginalna referencja i dlatego nie nastąpi wyrzucenie wyjątku w powyższym kodzie.

Natomiast w kodzie poniżej (do sygnatury metody zostało dodane słowo kluczowe ref):

   1: static void Main(string[] args)
   2: {
   3:     StringBuilder sb = new StringBuilder();
   4:     Method(ref sb);
   5:     Console.WriteLine(sb.ToString());
   6: }
   7:  
   8: static void Method(ref StringBuilder fooSB)
   9: {
  10:     fooSB.Append("test");
  11:     fooSB = null;
  12: }

Nastąpi już wyrzucenie wyjątku NullReferenceException, dlatego, że referencja do obiektu jest przekazywana przez referencje, a nie wartość i zmiana referencji w ciele metody, spowoduje zmianę oryginalnej referencji z metody Main.

A Ty wiedziałeś co się stanie?

Tags: ,
Categories: Techniczne

Permalink E-mail | Kick it! | DZone it! | del.icio.us Komentarze (2) Post RSSRSS comment feed

Komentarze

2011-11-07 20:03:17 #

flatplanet

Jeśli ostatnie pytanie nie jest retorycznymSmile to ja akurat wiedziałem ale tylko dlatego, że kiedyś poświęciłem wiele czasu nad rebusami z obiektówki.
W Twoim przykładzie tłumaczę sobie to tak, że zmienna fooSB wskazuje tylko na obiekt i "nulujemy" tylko jej wskazanie.
Analogiczny przykład:

            var foo = new StringBuilder();
            foo.Append("test");
            var lista = new List<StringBuilder>();
            lista.Add(foo);
            foo = null;

            var el1 = lista[0];

el1 nadal bedzie przechowywał obiekt przekazany przez foo.

flatplanet Poland

2011-11-07 20:20:56 #

daniel

@flatplanet
Dokładnie fooSB to referencja, czyli tak naprawdę adres, pod którym znajduje się docelowy obiekt i jej "nulowanie" nie powoduje w przypadków typów referencyjnych usuwania obiektu.

Dzięki za kolejny przykład Smile

daniel Poland

Dodaj komentarz


(Będzie pokazywało Gravatar ikon)

  Country flag

biuquote
  • Komentarz
  • Przegląd
Loading