将"is"关键字与"null"关键字一起使用 c# 7.0



最近我发现,以下代码在VS2017中按预期编译和工作。但是我找不到任何关于此的主题/文档。所以我很好奇使用这种语法是否合法:

class Program
{
static void Main(string[] args)
{
var o = new object();              
Console.WriteLine(o is null);
o = null;
Console.WriteLine(o is null);
Console.ReadLine();
}
}

顺便说一句,这在VS2015中不起作用

是的,写 o是空是有效的,但这并不等同于o == null。 代码

static bool TestEquality(object value) => value == null;

编译为以下 IL 指令。

IL_0000:  ldarg.0
IL_0001:  ldnull
IL_0002:  ceq
IL_0004:  ret

模式匹配案例按以下方式编译:

static bool TestPatternMatching(object value) => value is null;
IL_0000:  ldnull
IL_0001:  ldarg.0
IL_0002:  call       bool [System.Runtime]System.Object::Equals(object, object)
IL_0007:  ret

所以,模式匹配o 为 null等价于

Object.Equals(value, null);

因此,在大多数情况下,o 为null,o == null的行为方式相同。除了相等变体更快一些。但!如果我们用下面的类替换对象,事情将发生巨大变化。

class TestObject
{
public static bool operator ==(TestObject lhs, TestObject rhs) => false;
public static bool operator !=(TestObject lhs, TestObject rhs) => false;
}

和方法

static bool TestEquality(TestObject value) => value == null;
static bool TestPatternMatching(TestObject value) => value is null;

模式匹配将保持不变,但相等变体将在 IL 之后使用

IL_0000:  ldarg.0
IL_0001:  ldnull
IL_0002:  call       bool PatternMatchingTest.TestObject::op_Equality(class PatternMatchingTest.TestObject, class PatternMatchingTest.TestObject)
IL_0007:  ret

在这里我们可以看到,==运算符正在按预期使用TestObject的重载。但是o 是空的,o==null会给出不同的结果。所以要小心使用模式匹配运算符。

是的,这是完全有效的。这使用 C# 7 的模式匹配功能,该功能可用于is表达式和switch/case语句。(事实上,它需要 C# 7 是它在 VS2015 中不适合您的原因。例如:

// Type check, with declaration of new variable
if (o is int i)
{
Console.WriteLine(i * 10);
}
// Simple equality check
if (o is 5)  {}

像后者这样的相等性检查 - 特别是对于null- 对于is模式匹配可能不是很有用,但对于开关/案例更有用:

switch (o)
{
case int i when i > 100000:
Console.WriteLine("Large integer");
break;
case null:
Console.WriteLine("Null value");
break;
case string _:
Console.WriteLine("It was a string");
break;
default:
Console.WriteLine("Not really sure");
break;
}

有关 C# 7 功能的更多详细信息,请参阅 Mads Torgersen 的 MSDN 博客文章。

相关内容

最新更新