2009-08-31 10 views
13

Questo è più un 'chiedersi perché' di un problema specifico, ma guardare il seguente codicePerché implicitamente chiamando toString su un tipo di valore causare un'istruzione scatola

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

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


     } 

Nel caso in cui (1) la seguente IL è uscita

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) 

nel caso (2) dove ho esplicitamente chiamare il metodo toString ottengo

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) 

Quindi, nel caso (1), anche se int ignora toString, il tipo di valore viene imballato e il metodo toString viene chiamato che presumibilmente poi chiama la sostituzione vtable

Così il risultato è esattamente lo stesso, ma un tostring esplicito evita un'operazione boxe

Qualcuno sa perché?

= Edit =
OK per essere chiari, quello che mi confonde è che sto iniziando con il presupposto che anche se int deriva da System.ValueType, che a sua volta deriva da System.Object perché contiene toString, GetHashCode ecc.
Quindi nella mia vista ingenua (probabilmente da C++), se sovrascrivo un metodo derivato da System.Object, non è necessario eseguire il cast in System.Object (e quindi inserire il tipo di valore) perché esiste un metodo sovrascritto e il compilatore farà automaticamente riferimento alla voce vtable per il tipo.
Suppongo anche che chiamare Console.WriteLine() implicitamente chiama int.toString, quindi forse è lì che sbaglio. Spero che abbia senso

OK - tutto ordinato. Grazie a tutti per avermi sistemato. Tutto a che fare con una mia cattiva ipotesi che Console.WriteLine stava facendo una conversione di stringhe implicite. Non chiedetemi perché ho pensato che - sembra assolutamente ovvio quanto sia sbagliato che è ora :)

risposta

12

Non si sta chiamando implicitamente ToString affatto. Non c'è sovraccarico del metodo WriteLine che accetta stringhe dopo la stringa di formato, prende solo oggetti.

Quindi, non si sta chiamando implicitamente ToString, si sta convertendo implicitamente lo int in object. Il primo caso è equivalente a:

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

Come int è un tipo di valore, si verifica boxe.

Il secondo caso è equivalente a:

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

Poiché la stringa è un tipo di riferimento, colata per oggetto realtà non causa alcun codice da emessa. Corrisponde al tipo con la firma del metodo.

+0

Sì, è lì che sbaglio. Presumo che ci sia un cast implicito che si sta verificando. Ha senso ora! – zebrabox

4

causa in prima istanza si sta passando il int come object nel chiamare la funzione Console.WriteLine(). Ciò costringe lo int a essere inserito in una scatola. Nel secondo metodo invochi direttamente ToString, che evita il pugilato e passa un string a WriteLine, che è già un tipo di riferimento.

+0

Ma perché non quando int fornisce un override esplicito, quindi contiene una voce vtable per il metodo toString? – zebrabox

+0

@zebra: Non sono sicuro di cosa stai chiedendo. Di nuovo, l'operazione di boxing ha luogo perché l'int deve essere referenziato come un oggetto. Questo non accade nel secondo esempio perché una stringa viene passata a WriteLine, non a un int. –

+0

@Adam. Va tutto bene, tutto dipende da una mia cattiva ipotesi che stava accadendo una conversione implicita di toString. Ora so che non è vero è tutto chiaro di nuovo. Se Console.WriteLine accetta un oggetto, allora la scatola deve apparire come Jared Par ha detto di soddisfare i parametri del metodo – zebrabox

2

Nella prima chiamata non vi è alcuna chiamata .ToString. Invece stai chiamando la funzione Console.WriteLine (oggetto). Il primo parametro è di tipo int e deve essere inserito per soddisfare l'oggetto type. Più tardi all'interno di WriteLite, .ToString verrà chiamato sull'oggetto.

+0

Yep. Colpa mia. Stupida assunzione della mia - tutto chiaro ora. Saluti :) – zebrabox

Problemi correlati