问答中心分类: C#“x 为 null”和“x == null”有什么区别?
0
匿名用户 提问 13分钟 前

在 C# 7 中,我们可以使用

if (x is null) return;

代替

if (x == null) return;

与旧方法相比,使用新方法(前一个示例)有什么优势吗?
语义有什么不同吗?
这只是品味问题吗?如果没有,我什么时候应该使用其中一种?
参考:C# 7.0 中的新功能.

Simon Price 回复 13分钟 前

那是我刚刚查看的链接,但是它没有给您太多信息,这就是为什么我猜 OP 会问这个问题。页面最重要的部分是这个测试 is 运算符 “is”运算符用于检查对象的运行时类型是否与给定类型兼容。换句话说,我们使用“is”运算符来验证对象的类型是否符合我们的预期。让我们看看它的语法:

Simon Price 回复 13分钟 前

@SimonPrice 那是关于当前版本的C#:C# 6。这个问题是关于C# 7,它有模式匹配.

2 Answers
0
Thorkil Holm-Jacobsen 回答 13分钟 前

重载的等于运算符
实际上,当您进行比较时,两次比较之间的语义有所不同null具有重载的类型==操作员。foo is null将使用直接参考比较来确定结果,而foo == null当然会运行重载==运算符(如果存在)。
在这个例子中,我在重载中引入了一个“错误”==运算符,如果第二个参数是null

void Main()
{
    Foo foo = null;

    if (foo is null) Console.WriteLine("foo is null"); // This condition is met
    if (foo == null) Console.WriteLine("foo == null"); // This will throw an exception
}

public class Foo
{
    public static bool operator ==(Foo foo1, Foo foo2)
    {
        if (object.Equals(foo2, null)) throw new Exception("oops");
        return object.Equals(foo1, foo2);
    }

    // ...
}

IL代码为foo is null使用ceq执行直接参考比较的指令:

IL_0003:  ldloc.0     // foo
IL_0004:  ldnull      
IL_0005:  ceq

IL代码为foo == null使用对重载运算符的调用:

IL_0016:  ldloc.0     // foo
IL_0017:  ldnull      
IL_0018:  call        UserQuery+Foo.op_Equality

所以不同的是,如果你使用==您冒着运行用户代码的风险(可能会出现意外行为或性能问题)。
对泛型的限制
使用is null构造将类型限制为引用类型。编译器确保了这一点,这意味着您不能使用is null在值类型上。如果您有通用方法,您将无法使用is null除非泛型类型被限制为引用类型。

bool IsNull<T>(T item) => item is null;                  // Compile error: CS0403
bool IsNull<T>(T item) => item == null;                  // Works
bool IsNull<T>(T item) where T : class => item is null;  // Works

谢谢大卫奥古斯托别墅指出这一点。

David Augusto Villa 回复 13分钟 前

此外,如果 x 是泛型类型,则 note (x is null) 需要类约束,而 (x == null) 和 object.ReferenceEquals(x, null) 则不需要。

Majid Shahabfar 回复 13分钟 前

还应该注意的是,空合并运算符 (??) 和空合并赋值运算符 (??=) 像 “is” 也会忽略重载的等于运算符 (==)。

0
Frederic 回答 13分钟 前

当您尝试将非空变量与空值进行比较时,也会有所不同。使用时==,编译器会发出警告,而当使用is,编译器将发出错误。最有可能的是,99% 的情况下,您希望编译器会因为这样一个基本错误而对您大喊大叫。 +1 为is null.
在此处输入图像描述
在此处输入图像描述
PS 测试在https://dotnetfiddle.net/与NetCore3.1

Benjamin Sutas 回复 13分钟 前

这取决于您的视觉工作室设置。您可以轻松地告诉编译器将这些警告变成编译错误。

Frederic 回复 13分钟 前

@BenjaminSutas 实际上,您可以配置 VS 以更改默认行为。但默认行为通常是大多数用户所期望的行为。