Let's assume the following records (class).

record class Person(string? Identity, string Name, int Age, Address Address);
record class Address(string Country);

Before property pattern matching we did something like this.

if (person?.Identity != null && (person?.Age == 18 || (person?.Age >= 21 && person.Age <= 25))
    && person.Name.StartsWith("A")
    && person.Address.Country.Contains("land"))
{
    Console.WriteLine($"{person.Name} authorized.");
}

With property pattern matching we can do this in a more declarative way.
Combined with the var pattern we can write more readable and less code by using the newly created variables.

if (person is { Identity: not null, Name: var name, Age: 18 or >= 21 and <= 25, Address.Country: var country }
    && name.StartsWith("A")
    && country.Contains("land"))
{
    Console.WriteLine($"{name} authorized.");
}

We do NOT have to check for null with property pattern matching, because the C# compiler will "lowering" your high level C# code (syntax sugar) into lower level C# code (desugar).
See how C# lowering is done with sharplab

Nice to know: declarative vs imperative programming

  • With declarative programming you write code that describes what you want done.
  • With imperative programming, you write code that describes what you want step by step.

C# documentation:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns#property-pattern
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns#var-pattern