我只是参与Stack Overflow问题.NET中的所有内容都是对象吗?.
并且一张海报(在接受的答案的评论中)似乎认为对值类型执行方法调用导致拳击.他向我指出了Boxing和Unboxing(C#编程指南),它没有明确指出我们描述的用例.
我不是一个信任单一来源的人,所以我只是希望得到关于这个问题的进一步反馈.我的直觉是没有拳击,但我的直觉确实很糟糕.:d
进一步阐述:
我使用的例子是:
int x = 5; string s = x.ToString(); // Boxing??
如果有问题的结构覆盖从对象继承的方法,则不会发生拳击,如此处所接受的答案所述.
但是,如果结构不覆盖该方法,则在callvirt之前执行"约束" CIL命令.根据文档,OpCodes.Constrained Field,这导致拳击:
如果thisType是一个值类型而thisType没有实现方法,则ptr被解除引用,装箱,并作为'this'指针传递给callvirt方法指令.
plinth.. 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
所以这个案子的答案是否定的.
这是您的代码的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
所以这个案子的答案是否定的.
如果基座指出,在你给出答案的情况下是否定的.
但是,如果通过接口指针调用方法,它将会出现.
考虑一下代码:
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
@ 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; } } } }
主方法的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的文档,你会发现它表明拳击已经发生.OOO
引用:
如果thisType是一个值类型而thisType没有实现方法,则ptr被解除引用,装箱,并作为'this'指针传递给callvirt方法指令.