【问题标题】:Objects based on nullable types are only boxed if the object is non-null基于可空类型的对象仅在对象非空时才被装箱
【发布时间】:2016-01-16 11:25:06
【问题描述】:

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

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

【问题讨论】:

  • 尝试使用发布配置构建。

标签: c# ildasm


【解决方案1】:

尝试装箱值并不意味着它实际上是装箱值 - x 将是 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

至于在发布模式下编译 - 它可能不会尝试将值装箱,因为在编译时已知 anull - 如果 a 是public 方法,它可能总是会尝试将值装箱(但实际上从不装箱 null)。

【讨论】:

    【解决方案2】:

    您正在调试模式下编译代码。将其更改为 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,则处于发布模式的编译器将发出 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多