2009-08-31 10 views
13

Esto es más un 'preguntarse por qué' de un tema específico pero mira el siguiente código¿Por qué llamar implícitamente toString en un tipo de valor causar una instrucción de cuadro

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

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


     } 

En el caso (1) la siguiente IL es salida

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) 

en el caso (2) en la que pide explícitamente el método toString consigo

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) 

Así que en caso (1), a pesar de que int anula toString, el tipo de valor es en caja y el método toString se llama que, presumiblemente, a continuación, llama a la anulación vtable

Así, el resultado es exactamente el mismo, pero un toString explícita evita una operación de boxeo

Alguien sabe por qué?

= Editar =
bien ser clara, lo que me está confundiendo es que estoy empezando con el supuesto de que a pesar de int deriva de System.ValueType, que a su vez deriva de System.Object, ya que contiene toString, GetHashCode etc.
Por lo tanto, en mi vista ingenua (probablemente de C++), si anulo un método derivado de System.Object, entonces no hay necesidad de convertir a System.Object (y por lo tanto poner en cuadro el tipo de valor) porque existe un método overriden y el compilador referenciará automáticamente la entrada vtable para el tipo.
También estoy suponiendo que llamar a Console.WriteLine() implícitamente llama a int.toString, así que quizás sea allí donde me estoy equivocando. Espero que tenga sentido

OK - todo ordenado. Gracias a todos por haberme aclarado. Todo tiene que ver con una mala suposición de que Console.WriteLine estaba haciendo una conversión de cadena implícita. No me pregunte por qué pensé que - parece salta a la vista de lo equivocado que es ahora :)

Respuesta

12

No está llamando implícitamente ToString en absoluto. No hay sobrecarga del método WriteLine que toma cadenas después de la cadena de formato, solo toma objetos.

Así que no está llamando implícitamente ToString, está convirtiendo implícitamente int en object. El primer caso es equivalente a:

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

Como el int es un tipo de valor, el boxeo se produce.

El segundo caso es equivalente a:

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

A medida que la cadena es un tipo de referencia, la fundición a objeto en realidad no causa ningún código para ser emitida. Simplemente coincide con el tipo con la firma del método.

+0

Sí, ahí es donde me estoy equivocando. Supongo que hay un reparto implícito. ¡Tiene sentido ahora! – zebrabox

4

Debido a que en el primer caso que está pasando el int como object en llamar a la función Console.WriteLine(). Esto fuerza que el int esté en caja. En el segundo método, invoca directamente al ToString, lo que evita el boxeo y pasa un string al WriteLine, que ya es un tipo de referencia.

+0

Pero, ¿por qué no cuando int proporciona una anulación explícita, por lo que contiene una entrada vtable para el método toString? – zebrabox

+0

@zebra: No estoy seguro de lo que estás preguntando. Nuevamente, la operación de boxeo tiene lugar porque el int debe ser referenciado como un objeto. Esto no ocurre en el segundo ejemplo porque una cadena se pasa a WriteLine, no a int. –

+0

@Adam. Está bien, todo depende de una mala suposición de que estaba ocurriendo una conversión implícita de toString. Ahora sé que no es cierto, todo está claro nuevamente. Si Console.WriteLine acepta un objeto, el cuadro debe aparecer como Jared Par dijo que satisface los parámetros del método – zebrabox

2

En la primera llamada no hay ninguna llamada .ToString en absoluto. En su lugar, está llamando a la función Console.WriteLine (object). El primer parámetro es de tipo int y debe estar encuadrado para satisfacer el tipo de objeto. Más adelante dentro de WriteLite, se llamará .ToString al objeto.

+0

Sí. Mi error. Asunción estúpida mía, todo está claro ahora. Saludos :) – zebrabox

Cuestiones relacionadas