Short Version
How to make the C# nullable type checking compiler realize that the variable customer
cannot be null after the call returns:
Constraints.NotNull(customer);
Another Example
A better example, i came across in some old code:
Customer? currentCustomer;
//...
EnsureCurrentCustomer();
DoSomethingWithIt(currentCustomer); // guaranteed not null because EnsureCurrentCustomer did it,
// but the compiler doesn't know that.
We need a way for EnsureCurrentCustomer
to tell the C# 8 nullable type checker that the variable currentCustomer
cannot be null after EnsureCurrentCustomer
function returns.
How do?
Attempt 1: Null forgiving (!) operator
No. I want to work with the type system, not hide the land-mines (as Microsoft reminds you)
Attempt 2: https://stackoverflow.com/a/58282043/12597 (gives its own error)
Attempt 3: https://stackoverflow.com/a/65076221/12597 (No, see #1)
ChatGPT says the only way to do it is to use the JetBrains [NotNull]
constraint; which i don't have access to.
CodePudding user response:
If you just change the call site ever so slightly:
customer = Constraint.NotNull(customer, "Customer");
Then you can just do:
public static class Constraint {
public static T NotNull<T>(T? t, string? msg="") where T: notnull {
if (t is null) {
throw new Exception("Object cannot be null " msg);
}
return t;
}
}
For the second example, assuming currentCustomer
is a field, you can use MemberNotNull
:
[MemberNotNull("s")]
void EnsureCurrentCustomer() {
if (currentCustomer is null) {
throw new Exception(...);
}
}
If currentCustomer
is instead a local variable and EnsureCurrentCustomer
is actually a local function, then I would do something similar to Constraint.NotNull
, i.e. changing the caller to:
currentCustomer = EnsureCurrentCustomer()
and just use a non nullable Customer
for the return type.
CodePudding user response:
This is achieved using the [NotNull]
annotation on the argument being verified in your guard-clause method. A good reference for this is in the ArgumentNullException.ThrowIfNull
static method. The summary of the NotNullAttribute
says:
Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.
You can also refer to xUnit's Assert.NotNull
assertion, which does the same thing.