C#可以将值类型与null进行比较

Jos*_*den 85 c# null

我今天碰到了这个,并且不知道为什么C#编译器没有抛出错误.

Int32 x = 1;
if (x == null)
{
    Console.WriteLine("What the?");
}
Run Code Online (Sandbox Code Playgroud)

我很困惑x怎么可能是null.特别是因为这个赋值肯定会抛出编译器错误:

Int32 x = null;
Run Code Online (Sandbox Code Playgroud)

是否有可能x变为null,微软是否决定不将此检查放入编译器,还是完全错过了?

更新:在编写了这篇文章的代码后,编译器突然发出一个警告,表达式永远不会成立.现在我真的迷路了.我把对象放到一个类中,现在警告已经消失,但是留下了问题,值类型最终是否为null.

public class Test
{
    public DateTime ADate = DateTime.Now;

    public Test ()
    {
        Test test = new Test();
        if (test.ADate == null)
        {
            Console.WriteLine("What the?");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 118

这是合法的,因为运算符重载决策具有唯一的最佳运算符可供选择.有一个==运算符,它有两个可空的整数.int local可以转换为可以为null的int.null文字可以转换为可以为null的int.因此,这是==运算符的合法用法,并且总是会导致错误.

同样,我们也允许你说"if(x == 12.6)",这也总是假的.int local可以转换为double,文字可以转换为double,显然它们永远不会相等.

  • @James :(我收回了我之前删除的错误评论.)用户定义的值类型*默认情况下也定义了用户定义的相等运算符*,为它们生成了一个*提升的用户定义的相等运算符*.提升的用户定义的相等运算符适用于您声明的原因:所有值类型都可以隐式转换为相应的可空类型,null文本也是如此.**不是*缺少*用户定义的比较运算符的用户定义值类型与空文字相当的情况. (5认同)
  • 重新评论:http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?反馈ID = 348850 (4认同)
  • @James:当然,您可以实现自己的运算符==和运算符!=采用可为空的结构.如果存在,则编译器将使用它们而不是自动为您生成它们.(顺便说一句,我很遗憾在无可操作的操作数上对无意义的提升操作符的警告不会产生警告;这是编译器中的错误,我们还没有解决这个问题.) (3认同)
  • @JamesDunne:如何定义一个`static bool operator ==(SomeID a,String b)`并用`Obsolete`标记它?如果第二个操作数是一个无类型的文字"null",那么它将比任何需要使用提升运算符的形式更好地匹配,但如果它是一个`SomeID?`恰好等于`null`,则提升的运算符将获胜. (3认同)
  • 我们想要警告!我们应得的. (2认同)

Mar*_*ell 17

这不是错误,因为有一个(int?)转换; 它会在给出的示例中生成警告:

表达式的结果始终为"false",因为类型"int"的值永远不等于"int"类型的"null".

如果检查IL,您将看到它完全删除了无法访问的分支 - 它在发布版本中不存在.

但请注意,它不会为具有相等运算符的自定义结构生成此警告.它曾经用于2.0,但不是3.0编译器.代码仍然被删除(因此它知道代码无法访问),但不会生成警告:

using System;

struct MyValue
{
    private readonly int value;
    public MyValue(int value) { this.value = value; }
    public static bool operator ==(MyValue x, MyValue y) {
        return x.value == y.value;
    }
    public static bool operator !=(MyValue x, MyValue y) {
        return x.value != y.value;
    }
}
class Program
{
    static void Main()
    {
        int i = 1;
        MyValue v = new MyValue(1);
        if (i == null) { Console.WriteLine("a"); } // warning
        if (v == null) { Console.WriteLine("a"); } // no warning
    }
}
Run Code Online (Sandbox Code Playgroud)

使用IL(for Main) - 注意除了(可能有副作用)之外的所有内容MyValue(1)都已被删除:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] valuetype MyValue v)
    L_0000: ldc.i4.1 
    L_0001: stloc.0 
    L_0002: ldloca.s v
    L_0004: ldc.i4.1 
    L_0005: call instance void MyValue::.ctor(int32)
    L_000a: ret 
}
Run Code Online (Sandbox Code Playgroud)

这基本上是:

private static void Main()
{
    MyValue v = new MyValue(1);
}
Run Code Online (Sandbox Code Playgroud)

  • 最近也有人内部向我报告了这一点。我不知道为什么我们停止发出该警告。我们已将其作为错误输入。 (2认同)

Ada*_*son 5

比较永远不会成立的事实并不意味着它是非法的.尽管如此,不,价值类型永远都可以null.