4

我创建了一个简单的C#程序:

class Program
{
    static void Main(string[] args)
    {
        Int32? a = null;
        object x = a;
    }
}

根据 MSDN:

基于可空类型的对象仅在对象非空时才被装箱。如果 HasValue 为 false,则将对象引用分配给 null而不是装箱

我已经尝试了我的可执行文件,ILDASM发现IL代码调用了box方法。

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       17 (0x11)
  .maxstack  1
  .locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> a,
           [1] object x)
  IL_0000:  nop
  IL_0001:  ldloca.s   a
  IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<int32>
  IL_0009:  ldloc.0
  IL_000a:  box        valuetype [mscorlib]System.Nullable`1<int32>
  IL_000f:  stloc.1
  IL_0010:  ret
} // end of method Program::Main

我的问题是:为什么叫它?也许我做错了什么或误解了什么?

4

2 回答 2

6

尝试装箱值并不意味着它实际上是装箱值 - xwill be null,而不是装箱null。我认为 MSDN 试图解释这一点:

Int32? a = null;
object x = a;
object y = a;
object.ReferenceEquals(x, y); // true

但:

Int32? a = 3;
object x = a;
object y = a;
object.ReferenceEquals(x, y); // false

至于在发布模式下编译 - 它可能不会尝试对值进行装箱,因为在编译时已知- 如果a是公共方法的参数,它可能总是会尝试对值进行装箱(但实际上从不装箱)。nullanull

于 2015-10-17T22:05:03.897 回答
3

您正在调试模式下编译代码。将其更改为 Release,您将获得所需的行为。在这种情况下,它将一起省略分配:

.method private hidebysig static 

    void Main (string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2054
    // Code size 11 (0xb)
    .maxstack 1
    .locals init (
        [0] valuetype [mscorlib]System.Nullable`1<int32>
    )
    IL_0000: ldloca.s 0
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<int32>
    IL_0008: ldloc.0
    IL_0009: pop
    IL_000a: ret
} // end of method C::Main

如果您稍微更改代码并尝试接受 aInt?作为方法的参数,并null在编译时显式传递,则处于发布模式的编译器将发出一条box指令。

鉴于:

public void M(int? x) 
{
    object y = x;
    Console.WriteLine(y);
}
public void Main()
{
    M(null);
}

你会看到的:

.method public hidebysig 
 instance void M (
        valuetype [mscorlib]System.Nullable`1<int32> x
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 12 (0xc)
    .maxstack 8

    IL_0000: ldarg.1
    IL_0001: box valuetype [mscorlib]System.Nullable`1<int32>
    IL_0006: call void [mscorlib]System.Console::WriteLine(object)
    IL_000b: ret
} // end of method C::M

.method public hidebysig 
 instance void Main () cil managed 
{
    // Method begins at RVA 0x2060
    // Code size 16 (0x10)
    .maxstack 2
    .locals init (
        [0] valuetype [mscorlib]System.Nullable`1<int32>
    )
    IL_0000: ldarg.0
    IL_0001: ldloca.s 0
    IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
    IL_0009: ldloc.0
    IL_000a: call instance void C::M(valuetype [mscorlib]System.Nullable`1<int32>)
    IL_000f: ret
} // end of method C::Main
于 2015-10-17T22:07:59.080 回答