是否对通用原因装箱执行空检查?

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 将始终给出错误的结果,并删除盒子操作。