当将T与null进行比较,并且T是一个结构体时,CLR会执行什么操作?

8
private static void SaveOrRemove<T>(string key, T value)
{
    if (value == null)
    {
        Console.WriteLine("Remove: " + key);
    }

    //...
}

如果我传递0到value:SaveOrRemove("MyKey", 0),条件value == null是假的,那么CLR不会进行value == default(T)。实际上会发生什么?
3个回答

10
JIT编译器基本上会在T是非空值类型时,删除任何与null的比较,假设它们都为false。(可为空的值类型将与该类型的null值进行比较,这可能是您期望的。)如果您希望将其与默认值进行比较,则可以使用:
if (EqualityComparer<T>.Default.Equals(value, default(T))
{
    ...
}

1
作为一个附带说明,您不能拥有空值类型,因此它永远不会等于null。 - saret
我确信我已经看到一些失败的情况 - 最终使用装箱。 - Marc Gravell
@Marc:我非常想听听那些案例。@Saret:好的,你可以为可空值类型设置null值。我会编辑答案以包括这些内容。 - Jon Skeet
EqualityComparer<T>.Default.Equals和object.Equals有什么区别?我从来没有使用过EqualityComparer<T>.Default。 - Felipe Pessoto
@Fujiy:Object.Equals会对其参数进行装箱,如果您尝试比较不合适的类型,则在编译时不会告诉您。在大多数情况下,我认为这些将是唯一的差异,但重要的是,如果需要,您可以传递IEqualityComparer<T>-例如,在构造映射或集时。 - Jon Skeet
@Jon,我的错,我忘记了 Nullable<T>...它也是一个结构体。 - saret

5

您的问题在C#规范的第7.9.6节中有所解答:

如果将类型参数类型T的操作数与null进行比较,并且T的运行时类型是值类型,则比较的结果为false。


这不考虑可空值类型。 - Felipe Pessoto
3
@Fujiy :你说得很好。规范中确实缺少这种情况。我会向规范的作者们提出这个问题。 - Eric Lippert
出于好奇,规范不是由你们编写的吗?我问这个问题的原因是,我发现作家很难像你和C#团队一样熟悉实现细节,尝试编写像C#规范这样详细的东西。 - Joan Venge
2
@Joan: 我们撰写规范。Mads 最近大部分的写作工作都是由他完成的。其他人偶尔也会协助,像我或 VB 规范负责人 Lucian。像这样的小改变 - 只是将“值类型”更改为“非可空值类型” - 可能只会进入 Mads 的错别字清单中进行修复。更大的更改需要经过设计委员会的审核,以确保文字符合我们的要求。 - Eric Lippert
谢谢Eric。当你说规范作者时,我不知怎么就想到了像技术作家这样的普通作家。好知道。 - Joan Venge

0

如果你想要使用 default(T),你必须明确地写出来,而不是使用 null,因为它有自己的含义。如果你想要在值类型的位置上传递一个实际的 null,你应该使用 Nullable<T>

所以,你的代码应该变成这样:

private static void SaveOrRemove<T>(string key, Nullable<T> value)
{
    if (!value.HasValue()) // is null
    {
        Console.WriteLine("Remove: " + key);
    }
    else
    {
        T val = value.Value;
        // ...
    }
}

请注意,Nullable<T> 只有与值类型(结构体、字符串之外的“内建”类型)一起使用才有用;对于引用类型,无论如何都不能使用它。

MSDN链接


1
我个人会在这里使用if(value!= null),而不是显式调用HasValue。它具有相同的效果,但我偏好与null相关的语法糖 :) - Jon Skeet
我需要一个可以接受类和结构体的方法。这是一个会话包装器。 - Felipe Pessoto
@Jon Skeet:我也是这样想,但我觉得最好展示实际发生的事情。 - Chris Charabaruk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接