Será que chamar um método em um resultado de tipo de valor no boxe em .NET?
-
22-07-2019 - |
Pergunta
Eu estava apenas participando em questão Stack Overflow Está tudo em .NET um objeto? .
E um cartaz (em comentários de resposta aceita) parecia pensar que a realização de uma chamada de método em um tipo de valor resultou no boxe. Ele apontou-me a Boxing e Unboxing (C # Programming guia) , que não especifica exatamente o caso de uso que estamos descrevendo.
Eu não sou um para confiar em uma única fonte, então eu só queria obter mais feedback sobre a questão. Minha intuição é que não há nenhuma boxe, mas minha intuição é que chupar. : D
Para elaborar mais:
O exemplo que eu usei foi:
int x = 5;
string s = x.ToString(); // Boxing??
Boxe faz não ocorrer se a estrutura em questão substitui o método herdadas do objeto como a resposta aceito aqui afirma.
No entanto, se a estrutura não substitui o método, um "constrangimento" CIL comando é executado antes de uma callvirt. De acordo com a documentação, OpCodes. Constrained campo , isso resulta em boxe :
Se thisType é um tipo de valor e thisType não implementar o método então ptr é referência, encaixotado, e transmitido como o 'esta' ponteiro para o instrução método callvirt.
Solução
Aqui está o IL para o seu código:
L_0001: ldc.i4.5 // get a 5 on the stack
L_0002: stloc.0 // store into x
L_0003: ldloca.s x // get the address of x on the stack
L_0005: call instance string [mscorlib]System.Int32::ToString() // ToString
L_000a: stloc.1 // store in s
Portanto, a resposta, neste caso, não é.
Outras dicas
No caso de ter dado a resposta é não, como plinto apontou.
No entanto, ele vai se chamar um método através de um ponteiro interface.
Considere o código:
interface IZot
{
int F();
}
struct Zot : IZot
{
public int F()
{
return 123;
}
}
Em seguida
Zot z = new Zot();
z.F();
O não resultado no boxe:
.locals init (
[0] valuetype ConsoleApplication1.Zot z)
L_0000: nop
L_0001: ldloca.s z
L_0003: initobj ConsoleApplication1.Zot
L_0009: ldloca.s z
L_000b: call instance int32 ConsoleApplication1.Zot::F()
L_0010: pop
L_0011: ret
No entanto, isso faz:
IZot z = new Zot();
z.F();
.locals init (
[0] class ConsoleApplication1.IZot z,
[1] valuetype ConsoleApplication1.Zot CS$0$0000)
L_0000: nop
L_0001: ldloca.s CS$0$0000
L_0003: initobj ConsoleApplication1.Zot
L_0009: ldloc.1
L_000a: box ConsoleApplication1.Zot
L_000f: stloc.0
L_0010: ldloc.0
L_0011: callvirt instance int32 ConsoleApplication1.IZot::F()
L_0016: pop
"Eu acredito que chamar ToString, É igual e resultado GetHashCode em boxe, se a estrutura não faz substituir os métodos. "
Eu verifiquei ToString para você. Int32 faz override ToString, por isso fiz um struct que não. Eu costumava .NET Reflector para garantir que a estrutura não foi magicamente substituindo ToString () , e não foi.
Assim, o código foi assim:
using System;
namespace ConsoleApplication29
{
class Program
{
static void Main(string[] args)
{
MyStruct ms = new MyStruct(5);
string s = ms.ToString();
Console.WriteLine(s);
}
}
struct MyStruct
{
private int m_SomeInt;
public MyStruct(int someInt)
{
m_SomeInt = someInt;
}
public int SomeInt
{
get
{
return m_SomeInt;
}
}
}
}
E a MSIL (via ILDASM ) para o método principal é esta:
IL_0000: ldloca.s ms
IL_0002: ldc.i4.5
IL_0003: call instance void ConsoleApplication29.MyStruct::.ctor(int32)
IL_0008: ldloca.s ms
IL_000a: constrained. ConsoleApplication29.MyStruct
IL_0010: callvirt instance string [mscorlib]System.Object::ToString()
IL_0015: stloc.1
IL_0016: ldloc.1
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: ret
Agora, apesar de nenhuma chamada de boxe tomada lugar, se você verificar a documentação sobre um restrito + uma chamada virt , você vai encontrá-lo afirma que o boxe tem lugar. oOo
Citação:
Se thisType é um tipo de valor e thisType não implementar o método então ptr é referência, encaixotado, e transmitido como o 'esta' ponteiro para o instrução método callvirt.
Eu acredito que chamar ToString, iguais e resultado GetHashCode no boxe, se a estrutura não substitui os métodos.