基于可为空类型的对象仅在对象为非空时才装箱
Objects based on nullable types are only boxed if the object is non-null
我创建了一个简单的 C#
程序:
class Program
{
static void Main(string[] args)
{
Int32? a = null;
object x = a;
}
}
根据 MSDN:
Objects based on nullable types are only boxed if the object is non-null. If HasValue is false, the object reference is assigned to null instead of boxing.
我在 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
我的问题是:为什么叫它?
也许我做错了什么或误解了什么?
尝试对值进行装箱并不意味着它实际上是装箱值 - 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
至于在发布模式下编译 - 它 可能 不会尝试装箱值,因为在编译时已知 a
是 null
-如果 a
是 public 方法的参数,它可能总是会尝试装箱该值(但永远不会真正装箱 null
)。
您正在调试模式下编译代码。将其更改为发布,您将获得所需的行为。在这种情况下,它将一起省略赋值:
.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
我创建了一个简单的 C#
程序:
class Program
{
static void Main(string[] args)
{
Int32? a = null;
object x = a;
}
}
根据 MSDN:
Objects based on nullable types are only boxed if the object is non-null. If HasValue is false, the object reference is assigned to null instead of boxing.
我在 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
我的问题是:为什么叫它? 也许我做错了什么或误解了什么?
尝试对值进行装箱并不意味着它实际上是装箱值 - 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
至于在发布模式下编译 - 它 可能 不会尝试装箱值,因为在编译时已知 a
是 null
-如果 a
是 public 方法的参数,它可能总是会尝试装箱该值(但永远不会真正装箱 null
)。
您正在调试模式下编译代码。将其更改为发布,您将获得所需的行为。在这种情况下,它将一起省略赋值:
.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