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?
As Yari Halberstadt pointed out this is actually a compiler bug. I posted a question regarding this on the Csharplang discussions and was informed that this was already fixed.
As canton7 pointed out the issue was fixed recently and has at this point in time not been released yet.
Once released all example test-cases should pass. The failing test-case is actually a valid usecase according to this C#9 release blog where the following example is used: