我刚刚参与了Stack Overflow问题 Is everything in .NET an object? 。
一张海报(在接受回答的评论中)似乎认为对值类型执行方法调用会导致拳击。他向我指出了 Boxing and Unboxing (C# Programming Guide) ,它没有明确指出我们描述的用例。
我不是一个信任单一来源的人,所以我只是希望得到关于这个问题的进一步反馈。我的直觉是没有拳击,但我的直觉确实很糟糕。 :d
进一步阐述:
我使用的例子是:
int x = 5;
string s = x.ToString(); // Boxing??
如果有问题的结构覆盖了从对象继承的方法,那么
就会发生
但是,如果结构不覆盖该方法,则在callvirt之前执行“约束”CIL命令。根据文档, OpCodes.Constrained Field ,这导致拳击:
如果thisType是值类型而且 thisType没有实现方法 然后ptr被解除引用,装箱,和 作为'this'指针传递给 callvirt方法指令。
答案 0 :(得分: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
所以这个案子的答案是否定的。
答案 1 :(得分:11)
如果你给出答案是肯定的,那就像基座指出的那样。
但是,如果通过接口指针调用方法,它将会出现。
考虑代码:
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
答案 2 :(得分:7)
@ 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;
}
}
}
}
Main方法的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
现在,尽管没有发生拳击,但是如果你检查the documentation about a constrained + a call virt,你会发现拳击会发生。 OOO
引用:
如果thisType是值类型而且 thisType没有实现方法 然后ptr被解除引用,装箱,和 作为'this'指针传递给 callvirt方法指令。
答案 3 :(得分:4)
我相信如果结构没有覆盖方法,调用ToString,Equals和Gethashcode会导致装箱。