【问题标题】:Using "is" keyword with "null" keyword c# 7.0使用“is”关键字和“null”关键字 c# 7.0
【发布时间】:2017-04-08 14:14:30
【问题描述】:

最近我发现,以下代码在 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 中不起作用

【问题讨论】:

标签: c# null keyword c#-7.0


【解决方案1】:

是的,写o is null是有效的,但这不等于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 is null 等价于

Object.Equals(value, null);

因此,在大多数情况下,o 为 nullo == null 的行为方式相同。除了相等变体要快一点。 但是!如果我们将 object 替换为以下类,事情将会发生巨大变化。

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 is nullo==null 会给出不同的结果。所以要小心使用模式匹配 is 操作符。

【讨论】:

  • IL 看起来执行完全相同的相等性检查。你能解释一下与 C# 的区别吗?
  • 在上面的例子中,模式匹配相当于 Object.Equals(value, null) 方法调用,它将比较引用。而 value == null 相当于调用 TestObject 的相等静态方法 - TestObject.==(value, null),它通常可以做任何疯狂的事情。在下面的示例中,即使“value”为空引用,它也将始终返回 false
【解决方案2】:

是的,它完全有效。这使用了 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 功能的更多详细信息,请参阅MSDN blog post by Mads Torgersen

【讨论】:

  • 哦,我明白了。所以它就像一行中的类型检查、转换和比较。
  • @GorRustamyan:模式匹配目前主要是关于类型和相等性检查,带有用于 switch/case 的保护子句,但随着时间的推移它可能会显着扩展。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多