Reading the docs I am not 100% clear on the implications of pattern matching and assignment when checking nullability
Consider:
#nullable enable
record EmployeeData(string Name, int Age);
bool F(string employeeName) {
EmployeeData? employee = repository.Get(employeeName); // return null if not found
if (employee is null) return false;
// do something with employee it is not null
return true;
}
Can this correctly be written as:
bool F(string employeeName) {
if (repository.Get(employeeName) is not EmployeeData employee) return false;
// do something with employee it is not null
return true;
}
Note: I would like to do:
if (repository.Get(employeeName) as EmployeeData employee is null) return false;
which is much clearer, but that does not compile :( or is there a better way ?
CodePudding user response:
Let's try to prove employee
is not null.
We can start by finding out exactly when will the pattern not EmployeeData employee
match.
not EmployeeData employee
is a not
pattern with a declaration pattern EmployeeData employee
as its negated pattern. According to the documentation, a not
pattern
matches an expression when the negated pattern doesn't match the expression.
and
a declaration pattern with type
T
matches an expression when an expression result is non-null and any of the following conditions are true:
The run-time type of an expression result is
T
.The run-time type of an expression result derives from type
T
[...][...]
(I've omitted the rest of the conditions in that list because they are not relevant to your question)
Combining these two facts, we can see that your not EmployeeData employee
would match if the negation of the above quote is true, which is when
the expression result is null or all of the following conditions are true:
The run-time type of an expression result is not
T
.The run-time type of an expression result does not derive from type
T
[...][...]
This is when your if
branch would execute.
From your original code, it seems like repository.Get
is declared to return EmployeeData?
, so the expression result would always be of runtime type EmployeeData
or one of its derived type (nullable reference types don't exist in runtime), so the "all of the following conditions" part above would be always false. All that's left is the "the expression result is null".
Therefore, we have shown that your if
branch would execute when repository.Get(employeeName)
is null, which is the same as your original code.
If the if branch doesn't execute, then the code after it would. It also implies (by modus tollens) that repository.Get(employeeName)
is not null.
Since the value of repository.Get(employeeName)
is assigned to the declared employee
, as it said here:
With a declaration pattern, you can also declare a new local variable. When a declaration pattern matches an expression, that variable is assigned a converted expression result [...]
we have proven that employee
is not null.
CodePudding user response:
why don't you try
if (repository.Get(employeeName) is null) return false;