基于可空类型的对象仅在对象为非空

时间:2015-10-17 21:52:33

标签: c# ildasm

我创建了一个简单的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

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

2 个答案:

答案 0 :(得分:6)

设置值的尝试并不意味着它实际上是一个盒装值 - <div ng-app="customInterpolationApp" ng-controller="DemoController as demo"> //demo.label// </div> 将是x,而不是盒装null。我认为MSDN正试图解释:

null

可是:

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 - 如果{{1} }是一个公共方法的参数,它可能总是试图打包该值(但实际上从来没有框null)。

答案 1 :(得分: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

如果稍微更改代码并尝试接受Int?作为方法的参数,并在编译时显式传递null,则发布模式下的编译器将发出{{1指令。

假设:

box

你会看到:

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