/ / De quem ToString () seria chamado? - .net, boxe

Cujo ToString () seria chamado? - .net, boxe

Como sabemos, int tem ToString() método que substitui o ToString() método do tipo base Object.

Para este código a seguir,

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

(1) De quem ToString() seria chamado? int ou objeto? PORQUE?
(2) Como podemos verificar / ver a verdade? Por qualquer depuração / ferramenta?

Respostas:

3 para resposta № 1

Como o valor está na caixa, tudo o que o compilador conhece é object, portanto, é uma chamada virtual regular para object.ToString(), que selecionará a opção substituída ToString() da estrutura. Então é object.ToString() isso é invocado, e as Int32.ToString() sobrepor que é executado.

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

torna-se (comenta o meu):

.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
}

A linha importante está em L_000b; uma chamada virtual regular para object.ToString().

O que fica mais interessante é sem caixa tipos de valor; se um tipo de valor for conhecido ter um ToString(), ele pode emitir uma chamada 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
}

Veja a chamada estática (call) em L_0005. CONTUDO, na maioria dos casos de tipo de valor, ele usará um constrangido chamada, que será interpretada pelo JIT como uma chamada estática se é substituído e uma chamada virtual se isn "t:

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

torna-se:

.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
}

O par "restrito" / "chamada de chamada" em L_0010 e L_0016 juntos faça essa construção, para que não na realidade ser uma chamada virtual. O JIT / tempo de execução pode fazer outro vodu nele. Isto é discutido mais aqui.

Observe que um regular class vai sempre use chamada virtual para isso, exceto para o cenário return base.ToString();, que é uma chamada estática para a implementação dos tipos de base.


4 para resposta № 2

Int32.ToString() seria chamado, porque ToString() é chamado virtualmente. Int32.ToString() substitui Object.ToString(), portanto, em tempo de execução, ele substitui efetivamente Object.ToString().
E em tempo de execução, y é uma caixa int.


2 para resposta № 3

Int32, porque esse é o objeto real abaixo do cumprimento do mesmo contrato. Você pode verificar observando a saída. Se esse não fosse o caso, você teria "System.Object" retornado.


0 para a resposta № 4

Pensei que era java. Desculpe! :) int é um tipo primitivo. Todos os tipos primitivos são as únicas exceções em que a magia do OO para. Eles não herdam objetos, não são objetos! (Nenhum método toString, nenhum método em geral)

Inteiro, tem o método toString. Se seu exemplo foi com Integer, em vez de int, e seu objeto foi convertido para uma classe (como você fez no exemplo), se essa classe substitui toString (por exemplo, era sua classe personalizada) ou apenas o método toString (como Integer, por exemplo) class), esse método toString da classe deve ser chamado.

Caso contrário, o método toString da classe que herdou de deve ser chamado. Se não herdou de ninguém (significa: herdado da classe Object), a classe de objeto toString deve ser chamada.

Escrever um programa simples com algumas impressões pode ajudá-lo:

Integer x = new Integer(3);

impressão:

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

E nova classe anônima, igual a Inteiro, mas paraString Overriden

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

}
};

impressão:

y.toString();