使用 "is" 关键字和 "null" 关键字 c# 7.0

Using "is" keyword with "null" keyword c# 7.0

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

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 中不起作用

是的,完全正确。这使用了 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/case:[=17 更有用=]

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 功能的更多详细信息,请参阅 MSDN blog post by Mads Torgersen

是的,写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 将以相同的方式运行。除了平等变体有点快。 但是! 如果我们将 object 替换为以下 class,事情将会发生巨大的变化。

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 为 null 并且 o==null 将给出不同的结果。所以要小心使用模式匹配 is 运算符。