在C#7中,我们可以使用
if (x is null) return;
代替
if (x == null) return;
与旧方法相比,使用新方法(以前的示例)有什么优势?
语义有什么不同吗?
只是一个品味问题?如果没有,我什么时候应该使用另一个?
参考:C#7.0的新增功能。
在C#7中,我们可以使用
if (x is null) return;
代替
if (x == null) return;
与旧方法相比,使用新方法(以前的示例)有什么优势?
语义有什么不同吗?
只是一个品味问题?如果没有,我什么时候应该使用另一个?
参考:C#7.0的新增功能。
Answers:
更新: Roslyn编译器已更新,以在没有重载的相等运算符时使两个运算符的行为相同。请查看当前编译器结果(M1
和M2
代码)中的代码,该代码显示在没有重载的相等比较器时发生的情况。他们俩现在都表现更好==
。如果存在相等的比较器超载,则代码仍然不同。
有关较旧版本的Roslyn编译器,请参见以下分析。
因为null
与使用C#6的习惯没有什么区别。但是,当您更改null
为另一个常量时,事情变得很有趣。
以这个为例:
Test(1);
public void Test(object o)
{
if (o is 1) Console.WriteLine("a");
else Console.WriteLine("b");
}
测试合格a
。如果将其与o == (object)1
正常编写的内容进行比较,那确实会有所不同。is
考虑比较另一侧的类型。太棒了!
我认为== null
vs. is null
常量模式只是“偶然”非常熟悉的事情,其中is
运算符和equals运算符的语法产生相同的结果。
作为svick评论,is null
呼吁System.Object::Equals(object, object)
地方==
调用ceq
。
IL is
:
IL_0000: ldarg.1 // Load argument 1 onto the stack
IL_0001: ldnull // Push a null reference on the stack
IL_0002: call bool [mscorlib]System.Object::Equals(object, object) // Call method indicated on the stack with arguments
IL_0007: ret // Return from method, possibly with a value
IL ==
:
IL_0000: ldarg.1 // Load argument 1 onto the stack
IL_0001: ldnull // Push a null reference on the stack
IL_0002: ceq // Push 1 (of type int32) if value1 equals value2, else push 0
IL_0004: ret // Return from method, possibly with a value
既然我们在谈论null
,就没有区别,因为这仅对实例有所不同。当重载了相等运算符时,这可能会改变。
is
调用object.Equals(x, null)
,而==
编译为ceq
。但是结果应该和您说的一样。
is
在用于检查空值时不再具有函数调用的开销。为了证明,请参阅@svick在评论中发布的链接。
实际上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指出了这一点。