Pattern matching to find whether a value is not null
was done using the is
keyword with the respective expected type (included a cast if necessary). The pattern !(obj is object instance)
returns true
if obj
is not null
and false
if obj
is null
. At the same time if obj
is not null
it is captured in the variable instance
.
[Fact]
public void Old_pattern_matching_for_non_null_object()
{
var obj = new object();
if (!(obj is object instance)) // false
return;
if (instance is null) // false
throw new Exception("Never reached");
// this does not throw an exception (test passes)
}
With C#8 a new way of writing this was introduced using { }
to denote non-null
(without casting) which "simplified" the code to
[Fact]
public void Csharp_8_pattern_matching_for_non_null_object()
{
var obj = new object();
if (!(obj is { } instance)) // false
return;
if (instance is null) // false
throw new Exception("Never reached");
// this does not throw an exception (test passes)
}
With C#9 the new keyword not
was introduced which was intended to simplify patterns such as !(x is null)
to x is not null
. If I now try to apply the new not
keyword to a pattern includig { }
I get a quite surprising result:
[Fact]
public void Csharp_9_pattern_matching_for_non_null_object()
{
var obj = new object();
if (obj is not { } instance) // false
return;
if (instance is null) // true
throw new Exception("Why the heck is this null");
// this does throw an exception (test fails)
}
Even though that obj
is not null
the instance
variable is not initialized. And to get one better, by avoiding the obj
variable instance
will be initialized:
[Fact]
public void Csharp_9_pattern_matching_for_non_null_object_without_obj_variable()
{
if (new object() is not { } instance) // false
return;
if (instance is null) // false
throw new Exception("Never reached");
// this does not throw an exception (test passes)
}
Does anybody know if this is a desired behavior? If yes, what is the intent behind it?