/ / ¿De quién se llamaría ToString ()? - .net, boxeo

¿De quién se llamaría ToString ()? - .net, boxeo

Tal como lo conocemos, int tiene ToString() método que anula el ToString() método de tipo base Object.

Para este código siguiente,

int x = 100;
object y = (object)x;
Console.Write(y.ToString());

(1) Cuyo ToString() se llamaria? int u objeto? ¿POR QUÉ?
(2) ¿Cómo podemos verificar / ver la verdad? ¿Por cualquier depuración / herramienta?

Respuestas

3 para la respuesta № 1

Dado que el valor está encuadrado, todo lo que sabe el compilador es object, por lo que es una llamada virtual regular a object.ToString(), que luego recogerá el anulado ToString() de la estructura. Así es object.ToString() es decir invocado, y el Int32.ToString() anular que se ejecuta.

private static void Main()
{
int x = 100;
object y = (object)x;
Console.Write(y.ToString());
}

Se convierte en (comentarios míos):

.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] int32 x,
[1] object y)

// int x = 100;
L_0000: ldc.i4.s 100
L_0002: stloc.0

// object y = (object)x;
L_0003: ldloc.0
L_0004: box int32
L_0009: stloc.1

// Console.Write(y.ToString());
L_000a: ldloc.1
L_000b: callvirt instance string [mscorlib]System.Object::ToString()
L_0010: call void [mscorlib]System.Console::Write(string)
L_0015: ret
}

La línea importante está en L_000b; una llamada virtual regular a object.ToString().

Lo que se pone mas interesante es sin caja tipos de valor; si un tipo de valor es conocido tener un ToString(), entonces puede emitir una llamada estática:

private static void Main()
{
int x = 100;
Console.Write(x.ToString());
}

.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] int32 x)
L_0000: ldc.i4.s 100
L_0002: stloc.0
L_0003: ldloca.s x
L_0005: call instance string [mscorlib]System.Int32::ToString()
L_000a: call void [mscorlib]System.Console::Write(string)
L_000f: ret
}

Ver la llamada estática (call) a L_0005. SIN EMBARGO, en la mayoría de los casos de tipo valor utilizará un constreñido llamada, que será interpretada por el JIT como una llamada estática si es anulado, y una llamada virtual si no es:

private static void Main()
{
var x = new KeyValuePair<int, string>(123, "abc");
Console.Write(x.ToString());
}

se convierte en:

.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<int32, string> x)
L_0000: ldloca.s x
L_0002: ldc.i4.s 0x7b
L_0004: ldstr "abc"
L_0009: call instance void [mscorlib]System.Collections.Generic.KeyValuePair`2<int32, string>::.ctor(!0, !1)
L_000e: ldloca.s x
L_0010: constrained [mscorlib]System.Collections.Generic.KeyValuePair`2<int32, string>
L_0016: callvirt instance string [mscorlib]System.Object::ToString()
L_001b: call void [mscorlib]System.Console::Write(string)
L_0020: ret
}

El par "restringido" / "callvirt" en L_0010 y L_0016 juntos Hacer esta construcción, por lo que no podría actualmente ser una llamada virtual El JIT / tiempo de ejecución puede hacer otro vudú en él. Esto es discutido más aquí.

Tenga en cuenta que un regular class será siempre usar llamada virtual para esto, excepto para el escenario return base.ToString();, que es una llamada estática a la implementación de tipos base.


4 para la respuesta № 2

Int32.ToString() se llamaría, porque ToString() Se llama virtualmente. Int32.ToString() anula Object.ToString(), así que en tiempo de ejecución reemplaza efectivamente Object.ToString().
Y en el tiempo de ejecución, y es una caja int.


2 para la respuesta № 3

Int32, porque ese es el objeto real que se encuentra debajo y cumple el mismo contrato. Puede verificarlo observando la salida. Si este no fuera el caso, tendría que devolver "System.Object".


0 para la respuesta № 4

Pensé que era java. ¡Lo siento! :) int es un tipo primitivo Todos los tipos primitivos son las únicas excepciones donde se detiene la magia de OO. ¡No heredan objetos, no son objetos! (Sin método toString, no hay métodos en general)

Integer, tiene el método toString. Si su ejemplo fue con Integer, en lugar de int, y su objeto se convirtió en una clase (como lo hizo en su ejemplo), si esa clase anula toString (por ejemplo, era su clase personalizada), o simplemente ya tenía el método toString (como Integer clase), que clase de método toString debe ser llamado.

De lo contrario, se debe llamar al método toString de la clase que heredó de. Si no se heredó de nobody (significa: heredado de la clase Object), se debe llamar a la clase de objeto toString.

Escribir un programa simple con algunas impresiones puede ayudarte a:

Integer x = new Integer(3);

impresión:

x.toString()
((Object) x).toString();

Y nueva clase anónima, igual que Integer, pero toString Overriden

Integer y = new Integer(3){
@Override
String toString(){
return "WHATEVER!!";

}
};

impresión:

y.toString();