Использование ключевого слова" 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
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 от Mads Torgersen.
Да, действительно писать o равно 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 равно null эквивалентно
Object.Equals(value, null);
так, в большинстве случаев o is значение 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перегрузка, как и ожидалось. Но!--8-->o равно null и o==null даст различные результаты. Поэтому будьте осторожны, используя pattern matching is оператора.
