Qui*_*ome 24 .net boxing value-type
我只是参与Stack Overflow问题.NET中的所有内容都是对象吗?.
并且一张海报(在接受的答案的评论中)似乎认为对值类型执行方法调用导致拳击.他向我指出了Boxing和Unboxing(C#编程指南),它没有明确指出我们描述的用例.
我不是一个信任单一来源的人,所以我只是希望得到关于这个问题的进一步反馈.我的直觉是没有拳击,但我的直觉确实很糟糕.:d
进一步阐述:
我使用的例子是:
int x = 5;
string s = x.ToString(); // Boxing??
Run Code Online (Sandbox Code Playgroud)
如果有问题的结构覆盖从对象继承的方法,则不会发生拳击,如此处所接受的答案所述.
但是,如果结构不覆盖该方法,则在callvirt之前执行"约束" CIL命令.根据文档,OpCodes.Constrained Field,这导致拳击:
如果thisType是一个值类型而thisType没有实现方法,则ptr被解除引用,装箱,并作为'this'指针传递给callvirt方法指令.
pli*_*nth 17
这是您的代码的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
Run Code Online (Sandbox Code Playgroud)
所以这个案子的答案是否定的.
Rob*_*ker 11
如果基座指出,在你给出答案的情况下是否定的.
但是,如果通过接口指针调用方法,它将会出现.
考虑一下代码:
interface IZot
{
int F();
}
struct Zot : IZot
{
public int F()
{
return 123;
}
}
Run Code Online (Sandbox Code Playgroud)
然后
Zot z = new Zot();
z.F();
Run Code Online (Sandbox Code Playgroud)
难道不会导致拳击:
.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
Run Code Online (Sandbox Code Playgroud)
但是,这样做:
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
Run Code Online (Sandbox Code Playgroud)
@ ggf31316
"我相信如果结构不覆盖方法,调用ToString,Equals和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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
主方法的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
Run Code Online (Sandbox Code Playgroud)
现在,尽管没有发生拳击呼叫,如果你查看有关受限+呼叫virt的文档,你会发现它表明拳击已经发生.OOO
引用:
如果thisType是一个值类型而thisType没有实现方法,则ptr被解除引用,装箱,并作为'this'指针传递给callvirt方法指令.