Вызывает ли метод метод для типа значения в боксе в .NET?
Я просто участвовал в вопросе Является ли все в .NET объектом?.
И один плакат (в комментариях к принятому ответу), казалось, думал, что выполнение вызова метода по типу значения приводит к боксу. Он указал мне на "Бокс и Unboxing" (Руководство по программированию на С#), в котором точно не указан пример использования, который мы описываем.
Я не доверяю ни одному источнику, поэтому я просто хотел получить дополнительную информацию по этому вопросу. Моя интуиция заключается в том, что нет бокса, но моя интуиция действительно сосать.: D
Дальнейшая разработка:
В качестве примера я использовал:
int x = 5;
string s = x.ToString(); // Boxing??
Бокс не возникает, если рассматриваемая структура переопределяет метод, унаследованный от объекта, как утверждает принятый ответ.
Однако, если структура не переопределяет метод, перед вызовом callvirt выполняется команда "constrain" CIL. Согласно документации, OpCodes.Constrained Field, , это приведет к боксу:
Если этот тип является типом значения и thisType не реализует метод то ptr разыменовывается, помещается в коробку и передается как указатель 'this' на callvirt.
Ответы
Ответ 1
Здесь IL для вашего кода:
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
Таким образом, ответ в этом случае отсутствует.
Ответ 2
В случае, если вы дали ответ, нет, как указал цоколь.
Однако, если вы вызовете метод с помощью указателя интерфейса.
Рассмотрим код:
interface IZot
{
int F();
}
struct Zot : IZot
{
public int F()
{
return 123;
}
}
Тогда
Zot z = new Zot();
z.F();
Влияет ли не в бокс:
.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
Однако это делает:
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
Ответ 3
@ggf31316
"Я считаю, что вызов ToString, Равные и Gethashcode приводят к бокс, если структура не переопределить методы.
Я проверил ToString для вас. Int32 переопределяет ToString, поэтому я создал структуру, которая этого не делает. Я использовал .NET Reflector, чтобы гарантировать, что структура не была каким-то образом магически переопределяющим ToString(), и это не так.
Итак, код был таким:
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;
}
}
}
}
И MSIL (через ILDASM) для основного метода:
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
Теперь, несмотря на отсутствие бокс-звонка, если вы проверите документацию о принудительном + вызове virt, вы обнаружите, что это состояние что бокс имеет место. ööö
Цитата:
Если этот тип является типом значения и thisType не реализует метод то ptr разыменовывается, помещается в коробку и передается как указатель 'this' на callvirt.
Ответ 4
Я считаю, что вызов ToString, Equals и Gethashcode приводит к боксу, если структура не переопределяет методы.