2009-08-31 15 views
13

Jest to bardziej „Ciekawe dlaczego” niż konkretnego problemu, ale spojrzeć na poniższy kodDlaczego niejawnie wywołanie toString na typ wartości powodują dyspozycję skrzynki

 static void Main(string[] args) 
     { 
      int val = 10; 

      Console.WriteLine("val is {0}", val); // (1) 
      Console.WriteLine("val is {0}", val.ToString()); //(2) 


     } 

W przypadku (1) dodaje się IL jest wyjście

IL_0000: nop 
    IL_0001: ldc.i4.s 10 
    IL_0003: stloc.0 
    IL_0004: ldstr  "val is {0}" 
    IL_0009: ldloc.0 
    IL_000a: box  [mscorlib]System.Int32 
    IL_000f: call  void [mscorlib]System.Console::WriteLine(string, 
                   object) 

w przypadku (2), gdzie jawnie wywołać metodę toString uzyskać

IL_0014: nop 
    IL_0015: ldstr  "val is {0}" 
    IL_001a: ldloca.s val 
    IL_001c: call  instance string [mscorlib]System.Int32::ToString() 
    IL_0021: call  void [mscorlib]System.Console::WriteLine(string, 
                   object) 

Więc w przypadku (1), choć int nadpisuje toString, typ wartość jest zapakowane i metoda toString nazywa który przypuszczalnie wywołuje vtable nadpisanie

więc wynik jest dokładnie taki sam, ale wyraźne toString unika operacji Boks

Ktoś wie dlaczego?

= Edit =
OK, aby być jasne, co mnie mylące jest to, że zaczynam z założenia, że ​​mimo int pochodzi z System.ValueType, które z kolei wywodzi się z System.Object ponieważ zawiera toString, GetHashCode itd.
Tak więc w moim naiwnym widoku (prawdopodobnie z C++), jeśli przesłonię metodę wywodzącą się z System.Object, wtedy nie ma potrzeby rzutowania do System.Object (a stąd pole typu wartości), ponieważ istnieje metoda overriden i kompilator automatycznie odwoła się do pozycji vtable dla typu.
Zakładam również, że wywołanie Console.WriteLine() domyślnie dzwoni do int.toString, więc być może właśnie tam idę źle. Nadzieja, że ​​ma sens

OK - wszystkie posortowane. Dziękuję wszystkim za ustawienie mnie prosto. Wszystko co robiłem ze złym założeniem, że Console.WriteLine wykonywała niejawną konwersję ciągów znaków. Nie pytaj mnie, dlaczego uważam, że - jak wydaje się oślepiająco oczywiste, że źle jest teraz :)

Odpowiedz

12

Nie są Państwo w żaden sposób niejawnie wywołujący ToString. Nie ma przeciążenia metody WriteLine, która pobiera łańcuchy po ciągu formatu, pobiera tylko obiekty.

Tak więc, nie są Państwo niejawnie wywołujący ToString, niejawnie konwertuje się int na object. Pierwszy przypadek jest równoznaczne z:

Console.WriteLine("val is {0}", (object)val); 

Jako int jest typ wartości, boks występuje.

Drugi przypadek jest równoznaczne z:

Console.WriteLine("val is {0}", (object)val.ToString()); 

Ponieważ ciąg jest typ referencyjny, rzucając go do obiektu w rzeczywistości nie powodują jakiegokolwiek kodu być emitowane. Pasuje tylko do typu z podpisem metody.

+0

Tak, właśnie tam się mylę. Zakładam, że istnieje niejawna obsada. Ma sens teraz! – zebrabox

4

Ponieważ w pierwszej instancji jesteś minięciu int jako object w wywołaniu funkcji Console.WriteLine(). Zmusza to do boksowania int. W drugiej metodzie bezpośrednio wywołuje się ToString, co pozwala uniknąć boksowania i przekazuje string do WriteLine, która jest już typem odniesienia.

+0

Ale dlaczego nie, gdy int zapewnia jawne zastąpienie, więc zawiera wpis vtable dla metody toString? – zebrabox

+0

@zebra: Nie jestem pewien, o co pytasz. Ponownie, operacja boksu ma miejsce, ponieważ int musi być odniesiony jako obiekt. Nie dzieje się to w drugim przykładzie, ponieważ ciąg jest przekazywany do WriteLine, a nie do int. –

+0

@Adam. Wszystko w porządku, wszystko opiera się na złym mniemaniu, że nastąpiła niejawna konwersja toString. Teraz wiem, że to nieprawda, wszystko znowu jest jasne. Jeśli Console.WriteLine akceptuje obiekt, to pole musi wystąpić, gdy Jared Par powiedział, że spełnia warunki metody – zebrabox

2

W pierwszym wywołaniu nie ma żadnego połączenia .ToString. Zamiast tego wywołujesz funkcję Console.WriteLine (obiekt). Pierwszy parametr jest typu int i musi być w ramce, aby spełnić obiekt typu. Później wewnątrz WriteLite zostanie wywołany obiekt .ToString.

+0

Tak. Mój błąd. Głupie moje założenie - wszystko jasne teraz. Pozdrawiam :) – zebrabox

Powiązane problemy