是否对通用原因装箱执行空检查?
Does Performing a Null Check on a Generic Cause Boxing?
我环顾四周,找不到答案。假设我有这个代码:
class Command<T> : ICommand<T>
{
public void Execute(T parameter)
{
var isNull = parameter == null;
// ...
}
}
T
可以是任何 class,甚至 Nullable<>
。如果 T
是值类型,执行上述检查会导致装箱吗?我的理解是,这与调用 ReferenceEquals
相同,后者接受两个 object
参数,如果 T
是值类型,如果我理解正确的话,这两个参数中的任何一个都会导致装箱。
如果上述确实导致装箱,是否有更好的方法来做到这一点而不会导致装箱发生?我知道有 default(T)
但在 int
的情况下是 0
,我想看看这个值是否是 null
而不装箱。此外,我希望以一种同时满足值和引用类型的方式来执行此操作。
不——至少在我看来不是。如果 T
是不可空值类型,则 parameter == null
检查会被 JIT 编译器有效地替换为 false
;不执行执行时检查。
这是一种只有 JIT 编译器才能执行的优化,因为 C# 编译器只生成一种形式的代码。例如,为您的示例生成的 IL 是:
IL_0000: ldarg.1
IL_0001: box !T
IL_0006: ldnull
IL_0007: ceq
这似乎实际上执行了装箱 - 但我相信一个体面的 JIT 编译器会发现当 T
不可为空时,ceq
将始终给出错误的结果,并删除盒子操作。
我环顾四周,找不到答案。假设我有这个代码:
class Command<T> : ICommand<T>
{
public void Execute(T parameter)
{
var isNull = parameter == null;
// ...
}
}
T
可以是任何 class,甚至 Nullable<>
。如果 T
是值类型,执行上述检查会导致装箱吗?我的理解是,这与调用 ReferenceEquals
相同,后者接受两个 object
参数,如果 T
是值类型,如果我理解正确的话,这两个参数中的任何一个都会导致装箱。
如果上述确实导致装箱,是否有更好的方法来做到这一点而不会导致装箱发生?我知道有 default(T)
但在 int
的情况下是 0
,我想看看这个值是否是 null
而不装箱。此外,我希望以一种同时满足值和引用类型的方式来执行此操作。
不——至少在我看来不是。如果 T
是不可空值类型,则 parameter == null
检查会被 JIT 编译器有效地替换为 false
;不执行执行时检查。
这是一种只有 JIT 编译器才能执行的优化,因为 C# 编译器只生成一种形式的代码。例如,为您的示例生成的 IL 是:
IL_0000: ldarg.1
IL_0001: box !T
IL_0006: ldnull
IL_0007: ceq
这似乎实际上执行了装箱 - 但我相信一个体面的 JIT 编译器会发现当 T
不可为空时,ceq
将始终给出错误的结果,并删除盒子操作。