I'm a little bit confused about the "is" operator, using VS2022 and Resharper after writing this:
//signature for the record
Task<int?> getIntIdAsync()
//code inserted into some function
if(await getIntIdAsync() is not int id)
return false
As Resharper suggest, changing is not int id
to is not { } id
and hovering id
will result as int
, so no more nullable int?
in this case:
//signature for the record
Task<Location?> getLocationObjectAsync()
//code inserted into some function
if(await getLocationObjectAsync() is not Location loc)
return false
loc
will be a non-nullable Location
, but if i swap from is not Location loc
to is not { } loc
, hovering loc
show's a nullable Location?
object.
Can someone explain me why?
Isn't is not { }
meaning is not null
? So if a nullable Location?
is not null shouldn't be a Location
object?
The type pattern can be used to test values of nullable types: a value of type Nullable (or a boxed T) matches a type pattern T2 id if the value is non-null and the type of T2 is T, or some base type or interface of T. For example, in the code fragment
int? x = 3; if (x is int v) { // code using v }
The condition of the if statement is true at runtime and the variable v holds the value 3 of type int.
The type of loc
is Location
.
Let's consider this snippet:
#nullable enable
class Location {}
Location? l = new Location();
if(l is Location l2) Console.WriteLine(l2.GetType());
if(l is {} l3) Console.WriteLine(l3.GetType());
int? i = 3;
if(i is int i2) Console.WriteLine(i2.GetType());
if(i is {} i3) Console.WriteLine(i3.GetType());
This produces:
Submission#15+Location
Submission#15+Location
System.Int32
System.Int32
I suspect that Resharper sugget is (not) {}
pattern because it's more general.
Let's consider:
#nullable enable
using System.Runtime.CompilerServices;
void F(object arg1, [CallerArgumentExpression("arg1")] string arg1Exp = "?") => Console.WriteLine($"'{arg1Exp}' => {arg1}");
void CheckIfNull<T>(T o)
{
Console.WriteLine($"Value being checked is '{(o?.ToString() ?? "null")}'. Type: {typeof(T)}");
F(o is int); // This works only for int?/int
F(o is {}); // This works for all types
}
int? i = 3;
CheckIfNull(i);
string s = "Hello";
CheckIfNull(s);
This prints:
Value being checked is '3'. Type: System.Nullable`1[System.Int32]
'o is int' => True
'o is {}' => True
Value being checked is 'Hello'. Type: System.String
'o is int' => False <----- Oops. We just meant to check for null/not_null
'o is {}' => True
We can see that o is int for a string gives False
which may not be what you want if you're just checking for null / not_null.